对于C++的类而言,类的大小似乎并非完全由用户控制,我们看看如下的代码。
class X {};
class Y : public virtual X{};
class Z : public virtual X{};
class A : public Y, public Z{};
上述的X,Y,Z,A中没有任何一个class内含有明显的数据,其间只表示了继承关系,所以有人认为每个class的大小应该是0。当然不对,即使class X的大小也不是0。下面是测试结果。
GCC x86 64bit | Visual C++ 5.0 |
sizeof X的结果是 1 | sizeof X的结果是 1 |
sizeof Y的结果是 8 | sizeof Y的结果是 4 |
sizeof Z的结果是 8 | sizeof Z的结果是 4 |
sizeof A的结果是 16 | sizeof A的结果是 8 |
事实上Y和Z的大小受到三个因素的影响:
- 语言本身造成的额外负担(overhead) 当语言支持virtual base classes时候,就会造成一些额外的负担。在derived class中,这个额外的负担反映在某种形式的指针上,它或者指向virtual base class subobject,或者指向一个相关的表格;表格种存放的如果不是virtual base class subobject的地址,就是其偏移位置(offset)。
- 编译器对特殊情况所提供的优化处理 Virtual base class X subobject的1byte大小也出现在class Y和class Z身上。传统上它被放在derived class的固定部分尾部。某些编译器会对empty virtual base class 提供特殊支持。
- Alignment的限制 class Y和Z的大小截至目前是5 bytes。大部分的机器上,聚合的结构体大小会受到alignment的限制,使他们能够有效的在内存上存取。
PS:alignment就是将数值调整到某个数的整数倍。在32位计算机中,通常alignment为4bytes(32位),以使bus的“运输量”达到最高的效率。
Empty virtual base class已经成为C++ OO设计的一个特有术语了。他提供一个virtual interface,并没有定义任何的数据。在GCC x86 64Bit中,一个empty virtual base class被视作derived class object最开头的一部分,也就是说它没有花费任何的额外空间。以下是GCC x86 64Bit编译器对于class X,Y,Z的内存布局: