4

可能重复:
C++中的struct和class有什么区别

这个问题已经被问了很多,也得到了很多回答,但每隔一段时间我就会遇到一些令人困惑的事情。

总而言之,C++ 结构和类之间的区别在于著名的默认公共访问与私有访问。除此之外,C++ 编译器对待结构的方式与对待类的方式相同。结构可以有构造函数、复制构造函数、虚函数。等等。结构的内存布局与类的内存布局相同。C++ 具有结构的原因是为了与 C 向后兼容。

现在,由于人们对使用哪个结构或类感到困惑,因此经验法则是,如果您只有普通的旧数据,请使用结构。否则使用一个类。而且我已经读过结构在序列化方面很好,但不是从哪里来的。

然后前几天我看到了这篇文章: http: //www.codeproject.com/Articles/468882/Introduction-to-a-Cplusplus-low-level-object-model

它说如果我们有(直接引用):

struct SomeStruct
{ 
    int    field1;
    char   field2;
    double field3;
    bool   field4; 
};  

那么这个:

void SomeFunction()
{
    SomeStruct someStructVariable;
    // usage of someStructVariable
    ... 
}  

还有这个:

void SomeFunction()
{ 
    int    field1;
    char   field2;
    double field3;
    bool   field4;      
    // usage of 4 variables
    ... 
}

是相同的。

它说如果我们有一个结构或者只是写下函数内部的变量,生成的机器代码是相同的。当然,这仅适用于您的结构是 POD 的情况。

这就是我感到困惑的地方。在 Effective C++ 中,Scott Meyers 说没有空类这样的东西。

如果我们有:

class EmptyClass { };

它实际上是由编译器布置的,例如:

class EmptyClass
{
    EmptyClass() {}
    ~EmptyClass() {}
    ...
};

所以你不会有一个空的班级。

现在,如果我们将上述结构更改为一个类:

class SomeClass
{ 
    int  field1;
    char field2 
    double field3;
    bool  field4; 
}; 

这是否意味着:

void SomeFunction()
{
    someClass someClassVariable;
    // usage of someClassVariable
    ... 
}  

还有这个:

void SomeFunction()
{ 
    int  field1;
    char field2 
    double field3;
    bool  field4;      
    // usage of 4 variables
    ... 
}

在机器指令方面是否相同?没有调用 someClass 构造函数?或者分配的内存与实例化类或单独定义变量相同?那么填充呢?结构和类做填充。在这些情况下填充是否相同?

如果有人能对此有所了解,我将不胜感激。

4

4 回答 4

2

我相信那篇文章的作者是错误的。尽管这两个函数的结构和非成员变量布局版本之间可能没有区别,但我认为这不能保证。我能想到的唯一可以保证的是,因为它是一个 POD,所以结构的地址和第一个成员是相同的......并且每个成员在某个时间点之后都跟随在内存中。

在这两种情况下,由于它是一个 POD(类也可以是,不要犯那个错误),数据将被初始化。

我建议无论如何不要做出这样的假设。如果您编写的代码利用了它,而我无法想象您为什么要这样做,那么大多数其他开发人员都会觉得它莫名其妙。仅在必要时才翻阅法律书籍。否则更喜欢以人们习惯的方式编码。您真正应该记住的唯一重要部分是,POD 对象不会被初始化,除非您明确地这样做。

于 2012-10-08T04:11:13.670 回答
2

唯一的区别是结构的成员默认是公共的,而类的成员默认是私有的(当我说默认时,我的意思是“除非另有说明”)。看看这段代码:

#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;
}

代码编译并运行得很好。

于 2012-10-08T05:43:33.383 回答
1

除了默认保护之外,结构和类之间没有区别(请注意,基类的默认保护类型也不同)。书籍和我自己 20 多年的经验说明了这一点。

关于默认的空 ctor/dector。标准并没有要求这个。尽管如此,一些编译器可能会生成这对空的 ctor/dector。每个合理的优化器都会立即将它们扔掉。如果在某个地方调用了一个什么都不做的函数,你怎么能检测到呢?除了消耗 CPU 周期之外,这会如何影响任何事情?

MSVC 不会生成无用的函数。有理由认为每个优秀的编译器都会这样做。

关于例子

struct SomeStruct
{ 
    int    field1;
    char   field2;
    double field3;
    bool   field4; 
}; 

void SomeFunction()
{ 
    int    field1;
    char   field2;
    double field3;
    bool   field4;      
   ... 
}

填充规则、内存中的顺序等可能并且很可能会完全不同。优化器可能很容易丢弃未使用的局部变量。优化器从结构中删除数据字段的可能性要小得多(如果可能的话)。为此,应在 cpp 文件中定义结构,应设置某些标志等。

我不确定您是否会在堆栈上找到任何有关填充本地变量的文档。AFAIK,这是 100% 的编译器来制作这个布局。相反,描述了结构/类的布局,有#pargma控制它的命令行键等。

于 2012-10-08T04:27:59.373 回答
1

在机器指令方面是否相同?

没有理由不这样做。但是标准没有保证。

没有调用 someClass 构造函数?

是的,有一个对构造函数的调用。但是构造函数不起作用(因为所有成员都是 POD,并且您声明的方式someClass someClassVariable;会导致值初始化,这对 POD 成员没有任何作用)。因此,既然没有工作要做,就不需要种植任何指令。

或者分配的内存与实例化类或单独定义变量相同?

该类可能包含单独声明变量不包含的填充。
此外,我确信编译器会更轻松地优化单个变量。

那么填充呢?

是的,结构(结构/类)中可能存在填充。

结构和类做填充。在这些情况下填充是否相同?

是的。只要确保将苹果与苹果进行比较(即)

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; 
}; 
于 2012-10-08T06:03:41.737 回答