C++: Are Structs really the same as Classes?
Possible Duplicate:
What are the differences between struct and class in C++
号
这个问题被问过和回答了很多,但偶尔我会遇到一些令人困惑的问题。
总而言之,C++结构和类之间的区别是著名的默认公共访问和私有访问。除此之外,C++编译器以与对待类相同的方式对待结构。结构可以有构造函数、复制构造函数和虚拟函数。结构的内存布局与类的内存布局相同。C++具有结构的原因是与C的反向兼容。
现在,由于人们对使用哪一个、结构或类感到困惑,所以经验法则是,如果您只有简单的旧数据,那么就使用结构。否则使用类。我已经读到结构在序列化方面很好,但它不是从哪里来的。
前几天我看到了这篇文章:http://www.codeproject.com/articles/468882/introduction-to-a-cplusplus-low-level-object-model
它说如果我们有(直接引用):
1 2 3 4 5 6 7 | struct SomeStruct { int field1; char field2; double field3; bool field4; }; |
然后是:
1 2 3 4 5 6 | void SomeFunction() { SomeStruct someStructVariable; // usage of someStructVariable ... } |
号
还有这个:
1 2 3 4 5 6 7 8 9 | void SomeFunction() { int field1; char field2; double field3; bool field4; // usage of 4 variables ... } |
都是一样的。
它说,如果我们有一个结构或者只写下函数中的变量,生成的机器代码是相同的。当然,这只适用于你的结构如果一个pod。
这就是我困惑的地方。在有效的C++中,Scott Meyers说没有空类这样的东西。
如果我们有:
1 | class EmptyClass { }; |
。
它实际上是由编译器设计的,例如:
1 2 3 4 5 6 | class EmptyClass { EmptyClass() {} ~EmptyClass() {} ... }; |
所以你不会有一个空的班级。
现在,如果我们将上面的结构改为类:
1 2 3 4 5 6 7 | class SomeClass { int field1; char field2 double field3; bool field4; }; |
。
这是否意味着:
1 2 3 4 5 6 | void SomeFunction() { someClass someClassVariable; // usage of someClassVariable ... } |
。
还有这个:
1 2 3 4 5 6 7 8 9 | void SomeFunction() { int field1; char field2 double field3; bool field4; // usage of 4 variables ... } |
机器使用说明是否相同?没有调用SomeClass构造函数?或者分配的内存与实例化类或单独定义变量的内存相同?填充呢?结构和类进行填充。在这些情况下填充是否相同?
如果有人能解释一下,我会非常感激。
唯一的区别是结构的成员在默认情况下是公共的,而类的成员在默认情况下是私有的(当我说默认情况下,我的意思是"除非另有规定")。查看此代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #include <iostream> using namespace std; struct A { int x; int y; }; class A obj1; int main() { obj1.x = 0; obj1.y = 1; cout << obj1.x <<"" << obj1.y << endl; return 0; } |
号
代码编译并运行得很好。
我相信那篇文章的作者是错的。虽然这两个函数的结构和非成员变量布局版本之间可能没有区别,但我不认为这是有保证的。我能想到的唯一保证是,因为它是一个pod,所以结构和第一个成员的地址是相同的……并且每个成员在某个时刻都会在内存中跟随它。
在这两种情况下,由于它是一个pod(类也可以,不要犯那个错误),所以数据将被初始化。
无论如何,我建议不要做出这样的假设。如果您编写了利用它的代码,我无法想象您为什么要这样做,那么大多数其他开发人员都会觉得它令人困惑。只有在必要的时候,才可以打开法律书。否则更喜欢用人们习惯的方式来编码。所有这些中唯一重要的一点是,除非您明确地这样做,否则POD对象不会被初始化。
are the same in terms of machine instructions?
号
没有理由不去。但标准没有保证。
That there is no call to someClass constructor?
号
是的,有一个对构造函数的调用。但是构造函数不起作用(因为所有成员都是pod,并且您声明
Or that the memory allocated is the same as instantiating a class or defining the variables individually?
号
类可能包含单独声明变量的填充。此外,我相信编译器将有一个更容易的时间优化远离个别变量。
And what about padding?
号
是的,结构(结构/类)中可能存在填充。
structs and classes do padding. Would padding be the same in these cases?
号
对。你只要把苹果和苹果比较一下就行了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | struct SomeStruct { int field1; char field2; double field3; bool field4; }; class SomeStruct { public: /// Make sure you add this line. Now they are identical. int field1; char field2; double field3; bool field4; }; |
除了保护的默认值之外,结构和类之间没有区别(注意,基类的默认保护类型也不同)。书和我20多年的经验说明了这一点。
关于默认的空ctor/dector。标准不要求这样做。不过,有些编译器可能会生成这个空的ctor/dector对。每一个合理的优化器都会立即丢弃它们。如果在某个地方调用了一个不执行任何操作的函数,那么如何检测这个函数呢?除了消耗CPU周期之外,这会如何影响任何东西?
MSVC没有生成无用的函数。认为每一个好的编译器都会做同样的事情是合理的。
关于例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | struct SomeStruct { int field1; char field2; double field3; bool field4; }; void SomeFunction() { int field1; char field2; double field3; bool field4; ... } |
填充规则、内存顺序等可能和很可能完全不同。优化器很容易丢弃未使用的局部变量。优化器从结构中删除数据字段的可能性要小得多(如果可能的话)。要做到这一点,结构应该在cpp文件中定义,应该设置某些标志等。
我不确定您是否会在堆栈中找到任何有关本地变量填充的文档。Afaik,这100%取决于制作此布局的编译器。相反,结构/类的布局是描述的,有控制它的