------------------------------------------虚基派生类-----------------------------------------
class A class B: vitual public A class C: vitual public A class D: public B, public C
从虚基类A中直接派生(类B和类C)或间接派生(类D)的类中,其构造函数的初始化列表中都要
列出对虚基类A构造函数的调用,但只有用于创建对象的那个派生类的构造函数才能够真正调用虚基类A
构造函数,而该派生类的基类构造函数的初始化表中列出的对虚基类A的构造函数调用在执行时被忽略,
这样保证了对虚基类的子对象只初始化一次。
1 #include <iostream> 2 using namespace std; 3 class A //类A定义 4 { 5 private: //private成员列表 6 int x; 7 public: //public成员列表 8 A(int xp=0) //构造函数,带缺省参数 9 { 10 x=xp; 11 cout<<"A的构造函数被执行"<<endl; 12 } 13 ~A() //析构函数 14 { 15 cout<<"A的析构函数被执行"<<endl; 16 } 17 }; 18 class B:virtual public A //类B由类A虚基派生而来 19 { 20 public: 21 B(int xp):A(xp) //在初始化表中调用基类构造函数 22 { 23 cout<<"B的构造函数被执行"<<endl; 24 } 25 ~B() //析构函数 26 { 27 cout<<"B的析构函数被执行"<<endl; 28 } 29 }; 30 class C:virtual public A //类C由类A虚基派生而来 31 { 32 public: 33 C(int xp):A(xp) //在初始化表中调用基类构造函数 34 { 35 cout<<"C的构造函数被执行"<<endl; 36 } 37 ~C() //析构函数 38 { 39 cout<<"C的析构函数被执行"<<endl; 40 } 41 }; 42 class D:public B,public C //类D由类B和类C共同派生而来 43 { 44 public: 45 D(int xp):B(xp),C(xp),A(xp)
//初始化表中不仅要调用B类和C类的构造函数,还应调用共同虚基类的构造函数
46 { 47 cout<<"D的构造函数被执行"<<endl; 48 } 49 ~D() //析构函数 50 { 51 cout<<"D的析构函数被执行"<<endl; 52 } 53 }; 54 int main() 55 { 56 D expD(2); //声明D类对象expD 57 return 0; //main函数执行完毕退出后,expD撤销,析构函数触发执行 58 }
执行结果:
A的构造函数被执行
B的构造函数被执行
C的构造函数被执行
D的构造函数被执行
D的析构函数被执行
C的析构函数被执行
B的析构函数被执行
A的析构函数被执行
代码中,在创建D类对象expD时,D类的两个基类B和C的勾赵函数都被调用,但代码21行的类B和
代码33行的类C构造函数初始化表中的对虚基类A构造函数的调用被忽略了,执行的是类D构造函数初始
化表中列出的虚基类A的构造函数。
如果在程序中使用诸如 “ B expB(1); ” 的语句创建类B对象时,则在类B构造函数初始化表中列出的
对虚基类A构造函数的调用便会被执行,这解释了为什么要在虚基类派生路径上的每个类构造函数的初
始化表都要列出对虚基类构造函数的调用,这样便很好地保证了不管路径多深,虚基类的构造函数必须
且只能被调用一次。
注:C++规定,虚基类构造函数的执行要先于非虚基类构造函数的执行,同类构造函数的执行顺序
仍遵循类定义时的派生顺序,而不是出现在初始化表中的顺序。
析构函数的执行顺序与构造函数的执行顺序相反。
特别要说明的是一类特殊情况,即多虚基类的情况:
将类的定义简写如下:
class C : virtual public A, virtual public B class D : virtual public A, virtual public B class E : public C , public D |
各个类的构造函数简写如下所示:
C() : A() , B()
D() : A() , B()
E() : C() , D() , A() , B()
注意,定义时在前的类在图的左边,在创建E类对象时,按从左到右深度优先便利算法来调用各个
类的构造函数,如下所示:
(1) 初始化A类复制
(2) 初始化B类复制
(3) 初始化C类复制
(4) 初始化D类复制
(5) 初始化E类复制