虚基类

来源:互联网 发布:布吉岛漫画软件 编辑:程序博客网 时间:2024/06/16 17:52

一、虚基类的作用:

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

二、虚基类的特点:

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

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

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

详细分析见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 Basesize(4):1>  +---1>   0| a1>  +---1>  1>  class Derived1size(12):1>  +---1>   0| {vbptr}//虚基类指针1>   4| a1>  +---1>  +--- (virtual base Base)1>   8| a1>  +---1>  1>  Derived1::$vbtable@:1>   0| 01>   1| 8 (Derived1d(Derived1+0)Base)1>  1>  class Derived2size(12):1>  +---1>   0| {vbptr}1>   4| b1>  +---1>  +--- (virtual base Base)1>   8| a1>  +---1>  1>  Derived2::$vbtable@:1>   0| 01>   1| 8 (Derived2d(Derived2+0)Base)1> 1>  class SubDerivedsize(24):1>  +---1>  | +--- (base class Derived1)1>   0| | {vbptr}1>   4| | a1>  | +---1>  | +--- (base class Derived2)1>   8| | {vbptr}1>  12| | b1>  | +---1>  16| a       //该类自己定义的变量1>  +---1>  +--- (virtual base Base)   //仅有的一份共有Base基类1>  20| a1>  +---1>  1>  SubDerived::$vbtable@Derived1@:1>   0| 01>   1| 20 (SubDerivedd(Derived1+0)Base)1>  1>  SubDerived::$vbtable@Derived2@:1>   0| 01>   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"<<a<<endl;}int a;const int b;};class Derived1: virtual public Base{public:Derived1(int aa, int bb): Base(aa, bb){fun();}void fun(){cout<<"Derived1"<<a<<endl;}virtual void nonvirtualF(){}int c;};class Derived2: virtual public Base{public:Derived2(int aa, int bb): Base(aa, bb){fun();}void new_fun(){cout<<"Derived2"<<a<<endl;}virtual void nonvirtualF(){}int c;};class SubDrived: public Derived1, public Derived2{public:SubDrived(int aa, int bb):Base(aa, bb), Derived1(aa, bb), Derived2(aa, bb){}virtual void SubDrivedF(){}virtual void SubDrivedFF(){}virtual void SubDrivedFFF(){}int d;};类结构如下:1>  class Basesize(12):1>  +---1>   0| {vfptr}1>   4| a1>   8| b1>  +---1>  1>  Base::$vftable@:1>  | &Base_meta1>  |  01>   0| &Base::fun1>  1>  class Derived1size(28):1>  +---1>   0| {vfptr}   //两个虚函数指针,不同于单纯的虚函数继承1>   4| {vbptr}1>   8| c1>  +---1>  12| (vtordisp for vbase Base) //vtordisp域Vtordisp(虚基表到类的开始地址的偏移值)的MSDN的解释是:虚继承中派生类重写了基类的虚函数,并且在构造函数或者析构函数中使用指向基类的指针调用了该函数,编译器会为虚基类添加vtordisp域。产生vtordisp字段的条件是:1)派生类重写了虚基类的虚函数;2)派生类定义了构造函数或者析构函数。这两个条件缺一不可。1>  +--- (virtual base Base)1>  16| {vfptr}1>  20| a1>  24| b1>  +---1>  1>  Derived1::$vftable@Derived1@:1>  | &Derived1_meta1>  |  01>   0| &Derived1::nonvirtualF1>  1>  Derived1::$vbtable@:1>   0| -41>   1| 12 (Derived1d(Derived1+4)Base)1>  1>  Derived1::$vftable@Base@:1>  | -161>   0| &(vtordisp) Derived1::fun  //Base::fun被覆盖了1>  1>  class Derived2size(24):1>  +---1>   0| {vfptr}1>   4| {vbptr}1>   8| c1>  +---1>  +--- (virtual base Base)1>  12| {vfptr}1>  16| a1>  20| b1>  +---1>  1>  Derived2::$vftable@Derived2@:1>  | &Derived2_meta1>  |  01>   0| &Derived2::nonvirtualF1>  1>  Derived2::$vbtable@:1>   0| -41>   1| 8 (Derived2d(Derived2+4)Base)1>  1>  Derived2::$vftable@Base@:1>  | -121>   0| &Base::fun1>  1>  class SubDrivedsize(44):1>  +---1>  | +--- (base class Derived1)1>   0| | {vfptr}1>   4| | {vbptr}1>   8| | c1>  | +---1>  | +--- (base class Derived2)1>  12| | {vfptr}1>  16| | {vbptr}1>  20| | c1>  | +---1>  24| d1>  +---1>  28| (vtordisp for vbase Base)1>  +--- (virtual base Base)1>  32| {vfptr}1>  36| a1>  40| b1>  +---1>  1>  SubDrived::$vftable@Derived1@:1>  | &SubDrived_meta1>  |  01>   0| &Derived1::nonvirtualF1>   1| &SubDrived::SubDrivedF   //因为没有虚继承,所以SubDerived类没有单独生成vfptr来1>   2| &SubDrived::SubDrivedFF  //存放自己的虚函数,而是和单纯虚函数继承一样,将自己的1>   3| &SubDrived::SubDrivedFFF //虚函数放在该类的第一个继承的类的虚函数表中1>  1>  SubDrived::$vftable@Derived2@:1>  | -121>   0| &Derived2::nonvirtualF1>  1>  SubDrived::$vbtable@Derived1@:1>   0| -41>   1| 28 (SubDrivedd(Derived1+4)Base)1>  1>  SubDrived::$vbtable@Derived2@:1>   0| -41>   1| 16 (SubDrivedd(Derived2+4)Base)1>  1>  SubDrived::$vftable@Base@:1>  | -32 
0 0
原创粉丝点击