一个空的class如:
//sizeof(X) ==1
class X{};
事实上并不是空,它有一个隐藏的1byte大小,那是被编译器安插进去的一个char,这使得这一class的两个Object得以在内存中配置独一无二的地址:
X a,b;
if(&a == &b)
cerr<<"yipes"<<endl;
//sizeof(Y)==sizeof(Z)==8
class Y :public virtual X{};
class Z :public virtual X{};
Y和Z的大小都是8,这个大小和机器有关,也和编译器有关。事实上Y和Z的大小受到三个因素的影响:
1.语言本身所造成的额外负担。
当语言支持virtual base classes时,就会导致一些额外负担,在derived class中,这个额外负担反映在某种形式的指针身上,它或者指向virtual base class subobject,或者指向一个相关表格,表格中存放的不是virtual base class subobject的地址,就是其偏移量。
2.编译器对于特殊情况所提供的优化处理。
virtual base class subobject的1bytes大小也会出现在Y和Z身上。传统上他被放在derived的固定部分的尾端。某些编译器会对empty virtual base class提供特殊支持。
3.Alignment 的限制。
class Y和Z的大小截止目前位置为5bytes,在大部分机器上,聚合的结构体大小会受到alignment的限制。使它们能够更有效的在内存中被存取。alignment是4bytes,所以classY和Z必须填补3bytes,最终得到8bytes。
注意:alignment就是将数值调整到某数的整数倍。在32位计算机上,通常alignment为4bytes(32bit),以使bus的运输量达到最高效率。
某些编译器对此提供了特殊的处理。一个empty virtual base class被视为derived class Object最开头的一部分,也就是说它并没有花费任何的额外空间。这就节省了1bytes(因为既然有了members,就不需要原本为了empty class 而安插一个char),也就不再需要填补了。在此模型下,Y和Z的大小就是4而不是8.
C++对象模型尽量以空间优化和存取速度优化的考虑来表现nonstatic data members,并且保持和C语言struct数据配置的兼容性。他把数据直接存放在每一个class Object之中。对于继承而来的nonstatic data member输液室如此。
至于static data member ,则被放置在程序的一个global data segment中,不会影响个别的class的大小。在程序之中,不管该class被产生多少个Object,static data members永远只存在一份实例。但是一个Template class 的static data members的行为有所不同。
每一个class Object因此必须有足够的大小以容纳它所有nonstatic data members。有时候其值可能会更加大:
1.由编译器自动加上的额外data members,用以支持某些语言特性(主要是各种virtual 特性)
2.因为alignment(边界调整)的需要。