首先,您使用的是 a #pragma
,这可能会使您的编译器不标准;我不知道它在这里可能会产生什么影响,但这肯定意味着编译器可能会做一些奇怪的事情(包括以与任何其他接口完全不兼容的方式布置类)。
#pragma
话虽如此,无论有没有: 使用 g++ ,我都会得到相同的结果
,这些结果反映了你的结果;使用 VC++,派生类在所有情况下都得到 12。首先要注意的是,无论是private
还是public
,以及无论是 g++ 还是 VC++,基类的大小始终为 8。这是出于对齐考虑:两个编译器都尝试int
在 4 的倍数上保持对齐,并且为了做到this 在 的数组中Father
, 的总大小Father
必须为 8,在 . 之后有三个字节的填充c
。由于Child
还包含(通过继承间接地) an int
,因此适用相同的对齐注意事项。乍一看,我们期望
Child
大小为 12:8 个字节Father
, 加上 1 个字节的数据,加上 3 个字节的对齐填充。VC++ 就是这种情况。但是,C++ 标准允许一种叫做“空基类优化”的东西(因为它最初是为了让空基类不占用内存而设计的):它说的是当用作基类时,派生类可以重用任何填充在基地。所以Child
可以将它的成员e
放在 + 5 的地址Father
(因为那是填充Father
开始的地方),因此只需要 6 个字节(出于对齐原因,向上舍入为 8)。
为什么VC++不做这个优化,我不知道;也许他们受到优化名称的影响。(当基类没有数据成员时,他们会这样做。)为什么 g++ 只有在有私有成员而不是公共成员时才会这样做,这更奇怪,但标准并不要求它。
请注意,当应用优化时,类似于:
Father* p1 = new Child;
Father* p2 = new Child;
memcpy( p2, p1, sizeof(Father) );
可能会产生令人惊讶的后果,实际占用的空间大小Father
可能比所sizeof
指示的要小。这可能解释了选择 g++ 背后的逻辑:memcpy
如果类具有私有成员则无效,因此他们可以应用它;如果所有成员都是公共的(以及其他一些条件),则它是有效的,因此他们不应用它,以避免破坏上述内容。(添加一个构造函数,这也是memcpy
非法的,导致 g++ 应用优化。)