[C++11阅读][2-3-4]POD类型(中)

standard layout

本篇会简单涉及C++编译器如何在内存里排列成员变量。
标准布局指的是类的成员变量排布时,与C语言相同,按声明的顺序一个一个排。
需要符合以下条件才能做到这一点。

  1. 所有非静态成员有相同的访问权限(private、public、protected)
    不同访问权限的变量编译器会重排。
  2. 派生类中有非静态成员且只有一个仅包含静态成员的基类,或者,基类有非静态成员而派生类没有非静态成员
    简单地说,就是基类和派生类不能同时有非静态成员。
    仔细想想也好理解,派生类会包含基类的成员,如果两边都有,排布就会不标准了。
  3. 类中的第一个非静态成员的类型不能是基类
    这条规则很特别,是因为编译器做出的某项优化,导致本应该标准布局的情况变得不标准了,所以用这条规则来绕开这项优化。
    这项优化是:如果基类没有成员,标准允许派生类的第一个成员与基类共享地址。
    乍一看上去也不会影响排布,再一分析,如果派生类的第一个变量类型是基类,C++标准要求类型相同的对象必须地址不同,那么第一个变量和派生类变量就不能共享地址了,编译器会加一个字节的便宜,来强行错开派生类变量和派生类第一个成员变量。
    比如以下代码,d1的类型(基类类型)和d1.b的类型相同,编译器会给d1.b强行加1字节,d2就没这个限制,B1和B2是不同的类型。
#include 
using namespace std;
struct B1 {};
struct B2 {};
struct D1 : B1 {
    B1 b;
    int i;
};
struct D2 : B1 {
    B2 b;
    int i;
};
int main() {
    D1 d1;
    D2 d2;
    cout << hex;
    cout << reinterpret_cast(&d1) << endl;  // 7ffe2e9110e0
    cout << reinterpret_cast(&d1.b) << endl;  // 7ffe2e9110e1,多了1字节偏移
    cout << reinterpret_cast(&d1.i) << endl;  // 7ffe2e9110e4
    cout << reinterpret_cast(&d2) << endl;  // 7ffe2e9110f0
    cout << reinterpret_cast(&d2.b) << endl;  // 7ffe2e9110f0
    cout << reinterpret_cast(&d2.i) << endl;  // 7ffe2e9110f4
}
  1. 没有虚函数和虚基类
    这一点与trivial要求相同,避免虚函数表带来的问题。
  2. 所有非静态数据成员均符合标准布局类型,其基类也符合标准布局
    这一点没什么好说的,标准递归。

你可能感兴趣的:([C++11阅读][2-3-4]POD类型(中))