#pragma pack(push, 4)
class Father
{
public:
int b;
char c;
};
class Child : public Father
{
char e;
};
#pragma pack(pop)
的sizeof(父)= 8
的sizeof(儿童)= 12
但是如果我们像这样改变父亲类:
class Father
{
private:// change from public
int b;
char c;
};
的sizeof(儿童)= 8
答案 0 :(得分:5)
这是编译器的实现细节。换句话说,除非你真的真的需要让你的数据尽可能小,否则不是你的业务。请注意这里的过早优化。
最后,它可能归结为Common C ++ ABI的特性,使用诸如“POD用于布局”和“基类填充重用”之类的术语。
编辑:或者不是,因为这些编译指示建议您使用Visual Studio。在这种情况下,永远不要忘记MS ABI是一个狂野的向后兼容性黑客的丛林。
答案 1 :(得分:3)
您看到的大小差异是与C兼容的结果.C只知道所有内容都公开的struct
。因此,当您在C ++ public
或struct
中使用class
成员时,ABI与C兼容,因此它需要遵循C的对齐规则。
当您声明成员private
时,C ++ ABI可以更自由地优化成员的打包。
答案 2 :(得分:2)
首先,您使用的是#pragma
,这可能会让您感到满意
编译器非标准;我不知道它可能会产生什么影响
在这里,但它肯定意味着编译器可能做得很奇怪
事情(包括以完全相同的方式布置课程)
与任何其他接口不兼容)。
话虽如此,无论有没有,我都会得到相同的结果
#pragma
:使用g ++,这些结果反映了你的;用VC ++,
在所有情况下,我得到了12个派生类。第一件事
请注意,无论是private
还是public
,还是g ++或
VC ++,基类的大小始终为8.这是由于
对齐注意事项:两个编译器都试图保留int
对齐四个的倍数,并在一个
数组Father
,Father
的总大小必须为8,其中包含
c
之后填充的三个字节。自Child
以来也是如此
包含(间接通过继承)int
,相同
对齐考虑适用。乍一看,我们期待
Child
的大小为12:Father
的8个字节,加上
其数据为1个字节,加上3个字节填充用于对齐。这个
是VC ++的情况。但是,C ++标准允许
称为“空基类优化”的东西(因为它是
最初设计为允许空基类不占用
记忆):它说的是当用作基类时,
派生类可以重用基础中的任何填充。所以Child
可以
将其成员e
放在Father
+ 5的地址(因为那是
Father
中的填充开始的地方,因此只需要
6个字节(由于对齐原因,向上舍入为8)。
为什么VC ++没有做这个优化,我不知道;也许 他们受到优化名称的影响。 (他们是这样 当基类没有数据成员时这样做。)为什么g ++会这样做 只有有私人成员,而不是公开成员才会这样做 陌生人,但标准并不需要它。
请注意,应用优化后,例如:
Father* p1 = new Child;
Father* p2 = new Child;
memcpy( p2, p1, sizeof(Father) );
可能会产生令人惊讶的后果,实际上会占用空间
被Father
占用的可能小于sizeof
表示。这可能是选择背后的逻辑原因
g ++:如果类有私有成员,则memcpy
无效
他们可以申请;如果所有成员都是有效的话
公众(和其他一些条件),所以他们不适用它
为了避免破坏上述内容。 (添加
一个构造函数,它也使memcpy
非法,导致g ++
应用优化。)