C++ 中 class 的布局是什么?

What is the layout of a class in C++?

Here,有一段关于布局概念的Cclass.

Layout

When an object of some class C is created, each non-static data member of non-reference type is allocated in some part of the object representation of C. Whether reference members occupy any storage is implementation-defined.

For non-union class types, members with the same member access are always allocated so that the members declared later have higher addresses within a class object. Members with different access control are allocated in unspecified order (the compiler may group them together). Alignment requirements may necessitate padding between members, or after the last member of a class.

在 C++ 中是否有布局概念的严格等价物?

C++ 的标准布局是什么class?

常见实现中是否有引用成员的存储空间?

struct 的概念在 C 和 C++ 中很相似,但并不完全相同。结构成员的存储在 C11 中以类似的方式定义:

C11 6.7.2.1/6: a structure is a type consisting of a sequence of members, whose storage is allocated in an ordered sequence

ibid/14: Each non-bit-field member of a structure or union object is aligned in an implementationdefined manner appropriate to its type.

ibid/15: Within a structure object, the non-bit-field members and the units in which bit-fields reside have addresses that increase in the order in which they are declared.

但是这个定义的大部分是实现定义的,就像在 C++ 中一样。所以你没有任何保证,它是相同的内存布局。

事实上什至还有一个根本区别:在 C 中,指向第一个成员的指针总是保证是结构 对象的地址:

C11 6.7.2.1/15 ... A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa.

C++ 中你根本没有这样的保证。例如,采用这两个简单的 C++ 结构:

struct A { int a; }; 
struct B {
    int a;
    virtual void test() { }  // make the struct plymorphic
};

根据您的编译器,此示例中结构的地址可能与其第一个成员不同:

A a; B b;
cout << "&a=" << (void*)&a << " &a.a=" << (void*)&a.a << endl; 
cout << "&b=" << (void*)&b << " &b.a=" << (void*)&b.a << endl;

以MSVC2013为例,b.a的地址比b的地址高四个字节。这是因为编译器在对象的开头存储了一个指向虚拟函数和动态类型信息的 vtable 的指针。如前所述,这是实现定义的。请记住,您无法保证。

这强调了 C 结构概念不同于 C++ 的事实,因为没有构造函数和其他一些细微的语义差异。

在 C 中,您没有 reference 的概念。

C++ 中处理引用的方式是实现定义的。您可以将它们视为某种取消引用自身的指针,但不能保证您的编译器需要为引用存储任何东西(在某些情况下可能会被优化掉)。

该标准不强制执行任何布局规则,这就是为什么在不同的编译器和平台之间存在称为 "binary incompatibility" 的原因。

作为其 C 遗产的一部分,C++ 必须支持许多与 "common sense" 背道而驰的奇异平台,这就是为什么该标准不能为了支持这些平台而强制执行布局规则(现在大部分已经死了) ) 平台。