> 文章列表 > 015 - C++ 类与结构体对比

015 - C++ 类与结构体对比

015 - C++ 类与结构体对比

今天这期我们主要解决一个问题,就是 C++ 中的类和结构体有什么区别

上一期我们讲类的时候, 我们对类有了一些基本的介绍,在本期的学习开始之前你可以先看看那一期。

本期我们有两个术语,结构体 struct,它是 structure 的缩写,以及类 class。它们的用法看起来有点相似,很多人都会困惑他们之间的区别。你是应该使用 struct,还是应该使用一个 class,本期内容我们将搞清楚这些。

区别是这样的,——基本上没有区别。真的,它们之间只有一个关于可见度的小区别。

struct & class

上节内容我们讲过,一个类的成员默认为私有的(private)。这意味着如果我要做这样的事情,如果不加 public 的话,这里会得到一个错误。

015 - C++ 类与结构体对比

编译器告诉我们 Player 类中的 Move方法是不可访问的,因为它被标记为私有的(private)。如果我们想执行这段代码,——在类的外部去调用 Move 方法,我们必须在开始的位置必须写上 public。这就是区别的本质所在,默认情况下类是私有的,如果你不指定修改任何可见性,那默认值就是私有的私有的(private)。而在结构体中默认值却是公有的 (public) ,技术上讲这是类与结构的唯一区别。

如果把 class 改成 struct ,你可以试着运行上面的代码,一切就都好了,如果我真的想让某些东西是 private 的,在他们之前加上这个关键字就可以了。

015 - C++ 类与结构体对比

你会看到,这又把我们带回到类的相同错误了。

这个就是两者的区别。非常简单,这就是他们的全部。

使用上的区别

当然本期不可能只有这么点东西,我还想谈谈何时定义这两个词之间的区别,虽然从技术上讲他们可能没有太大区别,然而实际使用情况会有一些不同。

struct 结构体在 C++ 中继续存在的唯一原因,是因为它希望与 C 保持向后兼容性,因为C代码没有类,但是有结构体,如果我们去掉这个结构体关键字,就会失去兼容性,那样的话 C 的编译器就不知道什么是 struct。

当然它也可以很容易地解决这个问题,只需要用 #define 来查找,我们可以写一些类似于 #define 的东西来实现。

015 - C++ 类与结构体对比

这样能得到 C 与 C++ 的某种兼容性,在理想情况下,这样应该能将代码中的 struct 替换成 class,也就只能是这样了,在实际情况中不会有更多的区别了。

所以语义上的不同以及人们如何看待它,或多或少取决于用法,如果没有区别,那什么时候使用 struct 或者 class,如果我想要所有的成员都是公共的而不想写 public 这个字,那我应该使用结构体吗?真的就是些这么微不足道的区别吗?的确如此,它真的就是那么微不足道。

正因为如此,人们都有自己对于 struct 以及 class 的理解和定义。这并没有什么正确或错误的答案,这个取决于你的编程风格。

我来谈谈我的编程风格以及我可能在哪里使用每种类型。

我喜欢这样

每当我谈论 POD(Plain Old data)时,我喜欢尽可能的使用 struct。我说的是一种只表示变量的结构,一堆变量仅此而已。这方面一个很好的例子可能是数学上的向量类。

015 - C++ 类与结构体对比

定义一种 struct,把两个浮点数组合在一起。我把它定义为一种结构,有 x、y 两个浮点数。

从根本上说这个类,不管是用 class 还是 struct,都是代表这两个浮点数的一种结构。这个就是它的核心。他不应该像之前的 Player 类一样的,包含大量功能,——这个 Player 类可能有一个 3D 模型,它可能会为这个 3D 模型处理渲染代码,它可能处理比如 Player 如何在地图上移动并接收键盘输入,所有这些,可能有很多功能。

而我们这里是什么?它只是两个变量。我们把他们分组只是为了让我们的代码更容易使用,这就是我所做的。

当然这并不是说我不会添加方法到这里,其实完全可以我可能会添加一个名为add的方法。

015 - C++ 类与结构体对比

在上面的代码中,它取另外一个 Vec 作为参数,然后把它和自己的参数相加。

我只是在处理这些变量,只是添加了一个函数来处理这些变量。——到最后我都仍然只讨论这两个变量。

当然如果你真的要深入进去并认真思考,你可能会争论去说, Player 类不也只是操纵这些变量吗?

其实,在设计上还是有一点不同的,因为我们实际想要讨论的东西比你想象的要复杂的多。

另外的场景是继承。

我绝对不会在 struct 中使用继承,如果我要有一个完整的类层次结构,或者某种继承层次结构,我一定会使用类 class。因为继承是一种增加另一层次复杂性的东西。我只希望我的结构体是数据的结构,仅此而已。

除此之外,如果你尝试混合使用这些类型,举个例子你有一个 A 类和B 结构体,这个 B 结构体继承自 A,某些编译器会警告它继承了一个类,而它自己是结构体。——虽然是警告,但是仍然可以运行。

还有一些其他的小小的区别,暂且先不讨论了。

好吧,小小总结一下。

在这里我使用结构体而不是类的原因,是如果我只是想用结构体表示一些数据,我将使用一个结构体,如果我想要一个大量功能的整个类,比如一个游戏世界或者一个 Player,或者其他可能也有需要继承的东西,所有这些系统,我将使用一个类。这也是我个人区分这两种类型的方法。我了解到很多有经验的人也是这样的区分的,所以我建议你也这样做。

再说一次,你可以在任何可以使用类的地方使用结构体,它们将以相同的方式工作。

本期就是这些了,下期再见。