C++学习笔记(10)——虚基类的作用

  • Post author:
  • Post category:其他


本博客(

http://blog.csdn.net/livelylittlefish

)贴出作者(三二一、小鱼)相关研究、学习内容所做的笔记,欢迎广大朋友指正!


虚基类的作用


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

class CBase { };

class CDerive1:virtual public CBase{ };

class CDerive2:virtual public CBase{ };

class CDerive12:public CDerive1,CDerive2{ };

则在类CDerive12的对象中,仅有类CBase的一个对象数据

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

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

重写“C++学习笔记(9)——使用范围运算符解决继承中的二义性问题 ”中的程序,观察虚基类的作用
代码如下:





/*


***********************************************************************


* 混合继承:多基类继承与多重继承


***********************************************************************


*/





#include


<


IOSTREAM.H


>






//


基类






class


CBase







{





protected


:




int


a;




public


:


CBase(


int


na)







{



a


=


na;


cout


<<





CBase constructor!





;


}










~


CBase()




{cout


<<





CBase deconstructor!





;}





}



;






//


派生类1(声明CBase为虚基类)






class


CDerive1:


virtual




public


CBase







{





public


:


CDerive1(


int


na):CBase(na)







{



cout


<<





CDerive1 constructor!





;


}










~


CDerive1()




{cout


<<





CDerive1 deconstructor!





;}










int


GetA()




{



return


a;}





}



;






//


派生类2(声明CBase为虚基类)






class


CDerive2:


virtual




public


CBase







{





public


:


CDerive2(


int


na):CBase(na)







{



cout


<<





CDerive2 constructor!





;


}








~


CDerive2()




{cout


<<





CDerive2 deconstructor!





;}








int


GetA()




{



return


a;}





}



;






//


子派生类






class


CDerive12:


public


CDerive1,


public


CDerive2







{





public


:


CDerive12(


int


na1,


int


na2,


int


na3):CDerive1(na1),CDerive2(na2),CBase(na3)







{



cout


<<





CDerive12 constructor!





;


}








~


CDerive12()




{cout


<<





CDerive12 deconstructor!





;}





}



;




void


main()







{



CDerive12 obj(


100


,


200


,


300


);




//


得到从CDerive1继承的值






cout


<<





from CDerive1 : a =





<<


obj.CDerive1::GetA();




//


得到从CDerive2继承的值






cout


<<





from CDerive2 : a =





<<


obj.CDerive2::GetA()


<<


endl


<<


endl;


}

1. 子派生类对象的值:
从上例可以看出,在类CDerived12的构造函数初始化表中,调用了间接基类CBase的构造函数,这对于非虚基类是非法的,但对于虚基类则是合法且必要的。

对于派生类CDerived1和CDerived2,不论是其内部实现,还是实例化的对象,基类CBase是否是它们的虚基类是没有影响的。受到影响的是它们的派生类CDerived12,因为它从两条路径都能到达CBase。
2. 运行结果:
由此可知,其公共基类的构造函数只调用了一次,并且优先于非基类的构造函数调用;并且发现,子派生类的对象obj的成员变量的值只有一个,所以,当公共基类CBase被声明为虚基类后,虽然它成为CDerive1和CDerive2的公共基类,但子派生类CDerive12中也只有它的一个备份。可以仔细比较与例2的运行结果有什么不同。



版权声明:本文为livelylittlefish原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。