1、为何空类的大小不是0呢?
为了确保两个不同对象的地址不同,必须如此。
类的实例化是在内存中分配一块地址,每个实例在内存中都有独一无二的二地址。同样,空类也会实例化,所以编译器会给空类隐含的添加一个字节,这样空类实例化后就有独一无二的地址了。所以,空类的sizeof为1,而不是0.
2、请看下面的类:
class A{ virtual void f(){} };
class B:public A{}
此时,类A和类B都不是空类,其sizeof都是4,因为它们都具有虚函数表的地址。
3、请看:
class A{};
class B:public virtual A{};
此时,A是空类,其大小为1;B不是空类,其大小为4.因为含有指向虚基类的指针。
4、多重继承的空类的大小也是1.
class Father1{}; class Father2{};
class Child:Father1, Father2{};
它们的sizeof都是1.
5、何时共享虚函数地址表:
如果派生类继承的第一个是基类,且该基类定义了虚函数地址表,则派生类就共享该表首址占用的存储单元。对于除前述情形以外的其他任何情形,派生类在处理完所有基类或虚基类后,根据派生类是否建立了虚函数地址表,确定是否为该表首址分配存储单元。
6、扩展
首先,先看下面几个类:
class X{};
class Y : public virtual X {};
class Z : public virtual X {};
class A : public virtual Y {};
class B : public Y, public Z{};
class C : public virtual Y, public virtual Z {};
class D : public virtual C{};
在VC6.0上执行的结果为为:
sizeof(X):1
sizeof(Y):4
sizeof(Z):4
sizeof(A):8
sizeof(B):8
sizeof(C):12
sizeof(D):16
首先,对于class X,其实它并不是空的,它隐含着被编译器添加了一个char,那么为什么要添加这个char,我们来看,有这样的定义X x,则x肯定是又地址的,那既然x有地址,OK,sizeof(x)肯定就不为0了撒。
对于class Y和class Z,都有额外的负担,那么这个负担反映在指向virtual base class subobject上的指针。那照这样说,sizeof(Y)就应该等于5(先不考虑字节对齐)了?其实有些编译器提供了一些特殊处理,这使得一个empty virtual base class被视为derived class object最开头的一部分,也就是说它并没有花费任何空间,即这个1bytes被省了。
同样,对于class A,本身base class Y的大小为4,加个指针,则为8了。
对于class B,也很简单,class Y和class Z的大小都为4。
现在来看class C,因为他虚继承了Y和Z,所以它应该添加2个指针,在加上Y和Z,不应该是16么,那为什么结果是12呢?我们可以看到,Y和Z都是虚派生自class X,而一个virtual base class subobject只会在derived class中存在一份实体,不管它在class继承体系中出现了多少次。
如果说我把之前的类重新改下,新添加一个“class X1 {}; ”,而把class Z改成“class Z : public virtual X1 {}; ”,那么这个时候sizeof(C)就等于16了。
最后对于class D来说,应该很简单了