【问题标题】:C++: Are Structs really the same as Classes? [duplicate]C++:结构真的和类一样吗? [复制]
【发布时间】:2012-10-08 04:04:31
【问题描述】:

可能重复:
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

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

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 构造函数?或者分配的内存与实例化类或单独定义变量相同?那么填充呢?结构和类做填充。在这些情况下填充是否相同?

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

【问题讨论】:

  • 技术上struct 具有publicclass private 的默认继承访问权限。
  • 如果在阅读该文章时,您认为structclass 除了默认的成员访问保护级别之外有任何不同,那么您就得到了错误的印象。就这么简单。
  • -1:因为缺乏研究。我只在“”标题框中输入了您问题的标题。我在相关问题列表中得到的第一个问题(当然是在这个问题之后)是一个引导答案的(封闭的)问题。带有相关问题列表的框不仅仅是为了展示。
  • @NicolBolas 谢谢。我做了我的研究。我已经读过这个问题很多次了。然而,我的问题是关于上述文章和我感觉到的可能矛盾。我询问了构造函数、填充和汇编代码。如果您阅读了这个问题,您会发现我已经提到了公共与私人。我的问题是关于编译器生成的代码,这个问题没有讨论。我建议您在将我的标题输入“”之前阅读完整的问题。请阅读此问题中的一些答案,您就会明白。干杯。

标签: c++ class struct


【解决方案1】:

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

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

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

【讨论】:

    【解决方案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;
    }
    

    代码编译运行良好。

    【讨论】:

    • Ypu 忽略了 struct 基类默认是公共的,而 htey 对于类是私有的这一事实。
    【解决方案3】:

    除了默认的保护之外,结构和类之间没有区别(请注意,基类的默认保护类型也不同)。书籍和我自己 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和控制它的命令行键等等。

    【讨论】:

      【解决方案4】:

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

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

      没有调用 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; 
      }; 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-03-15
        • 1970-01-01
        • 2019-04-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-31
        • 2021-08-30
        相关资源
        最近更新 更多