私有成员和基类中的公共成员有什么区别?

时间:2013-09-17 09:52:52

标签: c++

#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

3 个答案:

答案 0 :(得分:5)

这是编译器的实现细节。换句话说,除非你真的真的需要让你的数据尽可能小,否则不是你的业务。请注意这里的过早优化。

最后,它可能归结为Common C ++ ABI的特性,使用诸如“POD用于布局”和“基类填充重用”之类的术语。

编辑:或者不是,因为这些编译指示建议您使用Visual Studio。在这种情况下,永远不要忘记MS ABI是一个狂野的向后兼容性黑客的丛林。

答案 1 :(得分:3)

您看到的大小差异是与C兼容的结果.C只知道所有内容都公开的struct。因此,当您在C ++ publicstruct中使用class成员时,ABI与C兼容,因此它需要遵循C的对齐规则。

当您声明成员private时,C ++ ABI可以更自由地优化成员的打包。

答案 2 :(得分:2)

首先,您使用的是#pragma,这可能会让您感到满意 编译器非标准;我不知道它可能会产生什么影响 在这里,但它肯定意味着编译器可能做得很奇怪 事情(包括以完全相同的方式布置课程) 与任何其他接口不兼容)。

话虽如此,无论有没有,我都会得到相同的结果 #pragma:使用g ++,这些结果反映了你的;用VC ++, 在所有情况下,我得到了12个派生类。第一件事 请注意,无论是private还是public,还是g ++或 VC ++,基类的大小始终为8.这是由于 对齐注意事项:两个编译器都试图保留int 对齐四个的倍数,并在一个 数组FatherFather的总大小必须为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 ++ 应用优化。)