虚基类
class A { public: int iValue; }; class B:public A { public: void bPrintf(){cout<<"This is class B"<<endl;}; }; class C:public A { public: void cPrintf(){cout<<"This is class C"<<endl;}; }; class D:public B,public C { public: void dPrintf(){cout<<"This is class D"<<endl;}; }; void main() { D d; cout<<d.iValue<<endl; //错误,不明确的访问 cout<<d.A::iValue<<endl; //正确 cout<<d.B::iValue<<endl; //正确 cout<<d.C::iValue<<endl; //正确 }
B C 都继承了A 他们都会有一个iValue的变量 而D又同时继承了 B C 当调用dprintf()时 不知道用哪个变量 所以就会产生二义性
1 class A 2 { 3 public: 4 int iValue; 5 }; 6 7 class B:virtual public A 8 { 9 public: 10 void bPrintf(){cout<<"This is class B"<<endl;}; 11 }; 12 13 class C:virtual public A 14 { 15 public: 16 void cPrintf(){cout<<"This is class C"<<endl;}; 17 }; 18 19 class D:public B,public C 20 { 21 public: 22 void dPrintf(){cout<<"This is class D"<<endl;}; 23 }; 24 25 void main() 26 { 27 D d; 28 cout<<d.iValue<<endl; //正确 29 }
在继承的类的前面加上virtual关键字表示被继承的类是一个虚基类,它的被继承成员在派生类中只保留一个实例。例如iValue这个成员,从类 D这个角度上来看,它是从类B与类C继承过来的,而类B C又是从类A继承过来的,但它们只保留一个副本。因此在主函数中调用d.iValue时就不 会产生错误。
总结
虚基类
1, 一个类可以在一个类族中既被用作虚基类,也被用作非虚基类。
2, 在派生类的对象中,同名的虚基类只产生一个虚基类子对象,而某个非虚基类产生各自的子对象。
3, 虚基类子对象是由最派生类的构造函数通过调用虚基类的构造函数进行初始化的。
4, 最派生类是指在继承结构中建立对象时所指定的类。
5, 派生类的构造函数的成员初始化列表中必须列出对虚基类构造函数的调用;如果未列出,则表示使用该虚基类的缺省构造函数。
6, 从虚基类直接或间接派生的派生类中的构造函数的成员初始化列表中都要列出对虚基类构造函数的调用。但只有用于建立对象的最派生 类的构造函数调用虚基类的构造函数,而该派生类的所有基类中列出的对虚基类的构造函数的调用在执行中被忽略,从而保证对虚基类子对象 只初始化一次。
7, 在一个成员初始化列表中同时出现对虚基类和非虚基类构造函数的调用时,虚基类的构造函数先于非虚基类的构造函数执行。