从下面的代码可以看出,sizeof(Base) == 24
,而且sizeof(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 字节对齐,但是它的最后一个成员大小为 4。这会导致在 Base
的内存布局末尾添加了一个空的填充区域。当你单独实例化 Base
类的对象时,这个额外的填充起到了作用,被称为所谓的“最派生对象”。
Base b; // <- a most-derived object
Base a[10]; // <- an array of most-derived objects
然而,当您将Base
作为基类“嵌入”到类Derived
中时,嵌入式Base
子对象末尾的额外填充是不必要的。
Derived d; // <- object `d` contains an embedded sub-object of type `Base`
一个智能的编译器将尝试重用该区域,通过将类Derived
的额外字段放置在Base
中用于填充的布局区域中。在您的情况下,额外的字段Derived::f
恰好具有4字节大小,即它完美地适合那里。最终结果是类的总大小不会增加。
一种非常相似(性质相似)的效果称为“空白基类优化”。在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
。
由于double和long的sizeof都等于8,这通常意味着alignof(double)也等于8。这意味着如果Base存储在数组中,它必须在8字节边界上进行大小对齐,并且它在末尾生成4字节的填充。Derived去掉填充以放置f。
alignof(double)
更相关,而不是与 sizeof(double)
相关。 - Marc Glisseclass 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 */
};
由于对齐需要而产生的填充:
虽然编译器(或解释器)通常在对齐边界上分配单个数据项,但数据结构经常具有具有不同对齐要求的成员。为了保持适当的对齐,翻译器通常插入额外的未命名数据成员,以便每个成员都正确对齐。此外,整个数据结构可能会用最终的未命名成员进行填充。这允许结构数组的每个成员都得到适当的对齐。
更多信息请参见:
http://en.wikipedia.org/wiki/Data_structure_alignment#Data_structure_padding
alignof(Base) == 4
,但是alignof(double) == 8
? - leemes