关于class:C ++:Structs和Classes真的一样吗?

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,并且您声明someClass someClassVariable;的方式会导致值初始化,这对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%取决于制作此布局的编译器。相反,结构/类的布局是描述的,有控制它的#pargma和命令行键等等。