(点击上方 offst(B::_a),
...
};
classB:virtualpublicA{
privat:
constint*vbtabl=vbtabl_of_B;
A_a;
};
每一个A的虚派生类,都会有自己的vbtabl表,这个派生类的所有实例共享这个表,然后每个实例各自保存了一个指向vbtabl表的指针。假如还有一个类C虚继承了A,那么编译器就会为它自动生成一个vbtabl_of_C的表,然后C的实例都会有一个指向这个vbtabl表的指针。
假如有多级的虚继承会发生什么情况,就像下面这段代码一样:
#includstdio.h
classA{
public:
inta;
};
classB:virtualpublicA{
public:
intb;
};
classC:virtualpublicB{
};
intmain(){
printf("%d\n",sizof(C));
rturn0;
}
程序运行的结果是16,按照之前的理论,大概会这么想。基类A里有1个变量,4个字节。B类虚继承了A,所以它有一个A的副本和一个vbtabl,还有自己的一个变量,那就是12字节。然后C类又虚继承了B类,那么它有一个B的副本,一个vbtabl,16字节。但实际上通过调试和反汇编发现,C中保存分别保存了A和B的副本(不包括B类的vbtabl),8字节。然后有一个vbtabl指针,4字节,表里面包含了A副本和B副本的偏移量。最后还有一个无用的4字节(?),一共16字节。不仅是这样,每经过一层的虚继承,便会多出4字节。这个多出来的四字节在反汇编中没发现实际用途,所以这个有待探讨,不管是编译器不够智能,还是有待其它作用,虚继承和多重继承都应该谨慎使用。
还是以上面的例子,假如C类是直接继承B类,而不是使用虚继承,那么C类的大小为12字节。它里面是直接保存了A和B的副本(不包含B的vbtabl),然后还有一个自己的vbtabl指针,所以一共12字节,没有了上一段所说的最后的4个字节。
但是如果想下面一种继承,会是什么情况?
#includstdio.h
classA{
public:
inta;
};
classB:virtualpublicA{
};
classC:virtualpublicA{
};
classD:publicB,publicC{
};
intmain(){
printf("%d\n",sizof(D));
rturn0;
}
D从B,C类派生出来,而B和C又同时虚继承了A。输出的结构是12,实际调试反汇编的时候发现,D中继承了B和C的vbtabl,这就是8字节,而同时还保存了一个A的副本,4字节,总共12字节。它和上面的多重虚继承例子里的12字节是不一样的。之前一个例子中只有一个vbtabl,一个A的实例,末尾还有一个未知的4字节。而这个例子中是有两个仅挨着的vbtabl(都有效)和一个A的实例。