C++中的虚继承

来源:互联网 发布:股票行情软件源码 编辑:程序博客网 时间:2024/04/29 09:35

多继承中被当做基类来虚继承的类是虚基类。

虚基类:使用关键字virtual继承的基类。即使同一类在层次中作为虚基类出现多次,派生类对象中虚基类部分也只出现一次。在非虚基类中,构造函数只能初始化自己的直接基类,当对一个类进行虚继承的时候,由最底层的派生类初始化那个类,因此最底层的派生类应包含用于其他所有虚父类的初始化式。

在这里有四个类:Point ,PointA,PointB,DerivedPoint。我给出头文件,不用给出源文件了:

[cpp] view plaincopy
  1. class Point    
  2. {  
  3. public:  
  4.     Point();  
  5.     virtual ~Point();  
  6.     int x,y;  
  7.   
  8. };  


 

[cpp] view plaincopy
  1. #include"Point.h"  
  2. class PointA :public virtual Point   
  3. {  
  4. public:  
  5.     PointA();  
  6.     virtual ~PointA();  
  7.     int a;  
  8.   
  9. };  


 

[cpp] view plaincopy
  1. #include"Point.h"  
  2. class PointB  :public virtual Point   
  3. {  
  4. public:  
  5.     PointB();  
  6.     virtual ~PointB();    
  7.     int b;  
  8.   
  9. };  


 

[cpp] view plaincopy
  1. #include"PointA.h"  
  2. #include"PointB.h"  
  3. class DerivedPoint :public PointA,public PointB   
  4. {  
  5. public:  
  6.     DerivedPoint();  
  7.     virtual ~DerivedPoint();  
  8.     int d;  
  9.   
  10. };  


PointA和PointB虚继承Point,DerivedPoint继承自PointA与PointB。

假定通过多个派生路径继承名为X的成员,有下面三种可能性:

1.如果在每个路径中X表示同一个虚基类成员,则没有二义性,因为共享该成员的单个实例。

2.如果在某个路径中X为虚基类成员,而在另一路径中X是后代派生类成员,也没有二义性------特定派生类实例的优先级高于共享虚基类实例。

3.如果沿每个继承路径X表示后代派生类的不同成员,则该成员的直接访问是二义性的。

特殊的初始化语意

从具有虚基类的类继承的类对初始化进行了特殊的处理。在虚派生中由最底层派生类的构造函数初始化虚基类

 

虽然由最底层派生类初始化虚基类,但是任何直接或者间接继承虚基类的类一般也必须为该基类提供自己的初始化式。只要可以创建虚基类派生类类型的对象,该类就必须初始化自己的虚基类部分,这些初始化式只在创建中间类型对象时使用。

有了以上的规则,我的类就应该如下写:

[cpp] view plaincopy
  1. class Point    
  2. {  
  3. public:  
  4.     Point();  
  5.     Point(int x,int y){this->x=x;this->y=y;};  
  6.     virtual ~Point();  
  7.     int x,y;  
  8.   
  9. };  


 

[cpp] view plaincopy
  1. #include"Point.h"  
  2. class PointA :public virtual Point   
  3. {  
  4. public:  
  5.     PointA();  
  6.     PointA(int x,int y,int a):Point(x,y),a(a)  
  7.     {};  
  8.     virtual ~PointA();  
  9.     int a;  
  10.   
  11. };  


 

[cpp] view plaincopy
  1. #include"Point.h"  
  2. class PointB  :public virtual Point   
  3. {  
  4. public:  
  5.     PointB();  
  6.     PointB(int x,int y,int b):Point(x,y){this->b=b;};  
  7.     virtual ~PointB();    
  8.     int b;  
  9.   
  10. };  


 

[cpp] view plaincopy
  1. #include"PointA.h"  
  2. #include"PointB.h"  
  3. class DerivedPoint :public PointA,public PointB   
  4. {  
  5. public:  
  6.     DerivedPoint();  
  7.     DerivedPoint(int x,int y,int a,int b,int d):PointA(x,y,a),PointB(x,y,b),Point(x,y),d(d){};  
  8.     virtual ~DerivedPoint();  
  9.     int d;  
  10.   
  11. };  

 

在主函数中调用如下:

[cpp] view plaincopy
  1. #include<iostream>  
  2. #include "DerivedPoint.h"  
  3. using namespace std;  
  4.   
  5. void main()  
  6. {  
  7.     DerivedPoint pt(1,2,3,4,5);  
  8.   
  9.     cout<<pt.x<<pt.y<<pt.a<<pt.b<<pt.d<<endl;  
  10.   
  11. }  


打印结果正常。

在这里首先构造虚基类,再构造PointA,PointB,DerivedPoint。在PointA和PointB中构造虚基类的调用被忽略。如果在DrivedPoint的构造函数中不显示调用Point的构造函数,就调用Point的默认构造函数,如果Point没有默认的构造函数,代码出错。

 

注意:虚基类的构造函数一定是最先调用

0 0