为什么是sizeof(BaseClass)== sizeof(DerivedClass),尽pipe我添加了一个成员

sizeof(Base) == 24sizeof(Derived) == 24下面的代码。

为什么他们的大小相等?

Base类中,我们有3个成员,在Derived类中,我们有另一个成员。

 class Base { private: double d; protected: long l; public: int i; }; class Derived : public Base { private: float f; }; 

它发生的事情就是你的类Base有8个字节的alignment要求,但最后一个成员的大小是4.这导致在Base的内存布局结尾添加一个空的填充区域。 当你通过自己实例化Base类的对象时,这个额外的填充就扮演了它的angular色,就像所谓的派生对象一样

 Base b; // <- a most-derived object Base a[10]; // <- an array of most-derived objects 

但是,当您将Base作为基类“embedded” Derived类时,不需要在embedded的Base子对象的末尾添加额外的填充。

 Derived d; // <- object `d` contains an embedded sub-object of type `Base` 

一个聪明的编译器会试图通过将Derived类的额外字段放入用于填充的布局区域来重用该区域。 在你的情况下,附加字段Derived::f顺便说一下有4个字节的大小,也就是说,它完全适合那里。 最终的结果是这个class的总人数不会增加。

一个非常相似的(本质上)效应就是所谓的“空基优化”。 在任何types的C ++ sizeof中保证大于0,这意味着空的类的sizeof总是大于零。 但是,当从一个空的基类中派生出其他一些类时,可能会发现基类对派生类的大小只贡献了0个字节。 例如

 struct A {}; struct B {}; struct C {}; struct D {}; struct F : A, B, C, D { int i; } int main() { std::cout << sizeof(A) << std::endl << sizeof(B) << std::endl << sizeof(C) << std::endl << sizeof(D) << std::endl; std::cout << sizeof(F) << std::endl; } 

即使每个基类的sizeof大于零, sizeof(F)仍将通常评估为sizeof(int) ,就好像基类子对象完全不存在一样。

换句话说,就像这样的例子所显示的那样,基类子对象在存储器布局方面比大多数派生对象遵循明显更宽松的规则。 这些宽松的规则可能很容易导致基类的sizeof只会部分地影响派生类的sizeof的情况。

因为你有sizeof(double)== sizeof(long)== 8,通常意味着alignof(double)也等于8。 这意味着Base必须在8个字节的边界上进行大小alignment,以防存储在一个数组中,并且在末尾生成一个4字节的填充,Derived将删除那个放置f。

使用pahole来弄清楚:

 class Base { private: double d; /* 0 8 */ protected: long int l; /* 8 8 */ int i; /* 16 4 */ /* size: 24, cachelines: 1, members: 3 */ /* padding: 4 */ /* last cacheline: 24 bytes */ }; class Derived : public Base { public: /* class Base <ancestor>; */ /* 0 24 */ /* XXX last struct has 4 bytes of padding */ private: /* Bitfield combined with next fields */ float f; /* 20 4 */ /* size: 24, cachelines: 1, members: 2 */ /* paddings: 1, sum paddings: 4 */ /* last cacheline: 24 bytes */ }; 

由于alignment需要填充:

尽pipe编译器(或解释器)通常在alignment的边界上分配单独的数据项,但是数据结构通常具有不同alignment要求的成员。 为了保持正确的alignment,翻译器通常会插入额外的未命名的数据成员,以便每个成员正确alignment。 另外,数据结构作为一个整体可以用最后的未命名成员填充。 这允许结构arrays的每个成员被正确alignment。

更多关于这里:
http://en.wikipedia.org/wiki/Data_structure_alignment#Data_structure_padding