虚基类

一、虚基类的作用:

当一个基类被声明为虚基类后,即使它成为了多继承链路上的公共基类,最后的派生类中也只有它的一个备份。

二、虚基类的特点:

虚基类构造函数的参数必须由最新派生出来的类负责初始化(即使不是直接继承);

虚基类的构造函数先于非虚基类的构造函数执行。

三、RTTI、虚函数和虚基类的开销分析:

虚基类_第1张图片

详细分析见http://baiy.cn/doc/cpp/inside_rtti.htm。

四、实例分析:

1、无虚函数的虚基类
class Base{
public:
	int a;
	Base(int aa):a(aa){}
};
class Derived1: virtual public Base{
public:
	int a;
	Derived1(int aa):Base(aa), a(aa){}
};
class Derived2: virtual public Base{
public:
	int b;
	Derived2(int aa):Base(aa), b(aa){}
};
class SubDerived: public Derived1, public Derived2{
public:
	int a;
	SubDerived(int a1, int a2, int a3, int a4):Derived1(a2), Derived2(a3), a(a4), Base(a1){}
};
类的结构如下:
1>  class Base	size(4):
1>  	+---
1>   0	| a
1>  	+---
1>  
1>  class Derived1	size(12):
1>  	+---
1>   0	| {vbptr}//虚基类指针
1>   4	| a
1>  	+---
1>  	+--- (virtual base Base)
1>   8	| a
1>  	+---
1>  
1>  Derived1::$vbtable@:
1>   0	| 0
1>   1	| 8 (Derived1d(Derived1+0)Base)
1>  
1>  class Derived2	size(12):
1>  	+---
1>   0	| {vbptr}
1>   4	| b
1>  	+---
1>  	+--- (virtual base Base)
1>   8	| a
1>  	+---
1>  
1>  Derived2::$vbtable@:
1>   0	| 0
1>   1	| 8 (Derived2d(Derived2+0)Base)
1> 
1>  class SubDerived	size(24):
1>  	+---
1>  	| +--- (base class Derived1)
1>   0	| | {vbptr}
1>   4	| | a
1>  	| +---
1>  	| +--- (base class Derived2)
1>   8	| | {vbptr}
1>  12	| | b
1>  	| +---
1>  16	| a       //该类自己定义的变量
1>  	+---
1>  	+--- (virtual base Base)   //仅有的一份共有Base基类
1>  20	| a
1>  	+---
1>  
1>  SubDerived::$vbtable@Derived1@:
1>   0	| 0
1>   1	| 20 (SubDerivedd(Derived1+0)Base)
1>  
1>  SubDerived::$vbtable@Derived2@:
1>   0	| 0
1>   1	| 12 (SubDerivedd(Derived2+0)Base)
2、有虚函数的虚继承
class Base{
public:
	Base(int aa, int bb): a(aa), b(bb){fun();}
	virtual void fun(){cout<<"Base"<  class Base	size(12):
1>  	+---
1>   0	| {vfptr}
1>   4	| a
1>   8	| b
1>  	+---
1>  
1>  Base::$vftable@:
1>  	| &Base_meta
1>  	|  0
1>   0	| &Base::fun
1>  
1>  class Derived1	size(28):
1>  	+---
1>   0	| {vfptr}   //两个虚函数指针,不同于单纯的虚函数继承
1>   4	| {vbptr}
1>   8	| c
1>  	+---
1>  12	| (vtordisp for vbase Base) //vtordisp域
Vtordisp(虚基表到类的开始地址的偏移值)的MSDN的解释是:虚继承中派生类重写了基类的虚函数,并且在构造函数或者析构函数中使用指向基类的指针调用了该函数,编译器会为虚基类添加vtordisp域。
产生vtordisp字段的条件是:
1)派生类重写了虚基类的虚函数;
2)派生类定义了构造函数或者析构函数。这两个条件缺一不可。
1>  	+--- (virtual base Base)
1>  16	| {vfptr}
1>  20	| a
1>  24	| b
1>  	+---
1>  
1>  Derived1::$vftable@Derived1@:
1>  	| &Derived1_meta
1>  	|  0
1>   0	| &Derived1::nonvirtualF
1>  
1>  Derived1::$vbtable@:
1>   0	| -4
1>   1	| 12 (Derived1d(Derived1+4)Base)
1>  
1>  Derived1::$vftable@Base@:
1>  	| -16
1>   0	| &(vtordisp) Derived1::fun  //Base::fun被覆盖了
1>  
1>  class Derived2	size(24):
1>  	+---
1>   0	| {vfptr}
1>   4	| {vbptr}
1>   8	| c
1>  	+---
1>  	+--- (virtual base Base)
1>  12	| {vfptr}
1>  16	| a
1>  20	| b
1>  	+---
1>  
1>  Derived2::$vftable@Derived2@:
1>  	| &Derived2_meta
1>  	|  0
1>   0	| &Derived2::nonvirtualF
1>  
1>  Derived2::$vbtable@:
1>   0	| -4
1>   1	| 8 (Derived2d(Derived2+4)Base)
1>  
1>  Derived2::$vftable@Base@:
1>  	| -12
1>   0	| &Base::fun
1>  
1>  class SubDrived	size(44):
1>  	+---
1>  	| +--- (base class Derived1)
1>   0	| | {vfptr}
1>   4	| | {vbptr}
1>   8	| | c
1>  	| +---
1>  	| +--- (base class Derived2)
1>  12	| | {vfptr}
1>  16	| | {vbptr}
1>  20	| | c
1>  	| +---
1>  24	| d
1>  	+---
1>  28	| (vtordisp for vbase Base)
1>  	+--- (virtual base Base)
1>  32	| {vfptr}
1>  36	| a
1>  40	| b
1>  	+---
1>  
1>  SubDrived::$vftable@Derived1@:
1>  	| &SubDrived_meta
1>  	|  0
1>   0	| &Derived1::nonvirtualF
1>   1	| &SubDrived::SubDrivedF   //因为没有虚继承,所以SubDerived类没有单独生成vfptr来
1>   2	| &SubDrived::SubDrivedFF  //存放自己的虚函数,而是和单纯虚函数继承一样,将自己的
1>   3	| &SubDrived::SubDrivedFFF //虚函数放在该类的第一个继承的类的虚函数表中
1>  
1>  SubDrived::$vftable@Derived2@:
1>  	| -12
1>   0	| &Derived2::nonvirtualF
1>  
1>  SubDrived::$vbtable@Derived1@:
1>   0	| -4
1>   1	| 28 (SubDrivedd(Derived1+4)Base)
1>  
1>  SubDrived::$vbtable@Derived2@:
1>   0	| -4
1>   1	| 16 (SubDrivedd(Derived2+4)Base)
1>  
1>  SubDrived::$vftable@Base@:
1>  	| -32 

你可能感兴趣的:(C++)