在visual C++ 6.0中测试如下代码:
#include "iostream"
using namespace std;
class X {};
class Y : public virtual X {};
class Z : public virtual X {};
class A : public Y,public Z {};
int main()
{
cout<<"sizeof(X): "<<sizeof(X)<<endl;
cout<<"sizeof(Y): "<<sizeof(Y)<<endl;
cout<<"sizeof(Z): "<<sizeof(Z)<<endl;
cout<<"sizeof(A): "<<sizeof(A)<<endl;
return 0;
}
得出的结果也许会令你毫无头绪
sizeof(X): 1
sizeof (Y): 4
sizeof(Z): 4
sizeof(A): 8
下面一一阐释原因:
(1)对于 一个class X这样的空的class,由于需要使得这个class的两个objects得以在内存中配置独一无二的地 址,故编译器会在其中安插进一个char.因而class X的大小为1.
(2)由于class Y虚拟继承于 class X,而在derived class中,会包含指向visual base class subobject的指针(4 bytes),而由 于需要区分这个class的不同对象,因而virtual base class X subobject的1 bytes也出现在class Y中 (1 bytes),此外由于Alignment的限制,class Y必须填补3bytes(3 bytes),这样一来,class Y的 大小为8.
需要注意的是,由于Empty virtual base class已经成为C++ OO设计的一个特有术语, 它提供一个virtual interface,没有定义任何数据。visual C++ 6.0的编译器将一个empty virtual base class视为derived class object最开头的一部分,因而省去了其后的1 bytes,自然也不存在后面 Alignment的问题,故实际的执行结果为4.
(3)不管它在class继承体系中出现了多少次,一个 virtual base class subobject只会在derived class中存在一份实体。因此,class A的大小有以下几 点决定:(a)被大家共享的唯一一个class X实体(1 byte);(b)Base class Y的大小,减去 “因virtual base class X而配置”的大小,结果是4 bytes.Base class Z的算法亦同。 (8bytes)(c)classs A的alignment数量,前述总和为9 bytes,需要填补3 bytes,结果是12 bytes.
考虑到visual C++ 6.0对empty virtual base class所做的处理,class X实体的那1 byte将被拿掉,于是额外的3 bytes填补额也不必了,故实际的执行结果为8.
不管是自身class的 还是继承于virtual或nonvirtual base class的nonstatic data members,其都是直接存放在每个class object之中的。至于static data members,则被放置在程序的一个global data segment中,不会影响 个别的class object的大小,并永远只存在一份实体。
***Data Member的绑定***
早期 C++的两种防御性程序设计风格的由来:
(1)把所有的data members放在class声明起头处,以 确保正确的绑定:
class Point3d
{
// 在class声明起头处先放置所有的data member
float x,y,z;
public:
float X() const { return x; }
// ...
};