C++虚继承的意义

C++虚继承可以防止多重继承产生的二义性问题。

        虚继承,就是在被继承的类前面加上virtual关键字,这时被继承的类称为虚基类,如下面代码中的base类。虚继承在多重继承的时可以防止二义性。

    class base

    class derived1 : virutal public base

    class derived2 : virtual public base

    class derived3 : public derived1, public derived2

以上的代码如果用到了base中的某个成员变量就不会产生二义性。和#progma once在头文件中的作用类似。请看下面的例子:

[cpp]  view plain  copy
  1. #include <iostream>  
  2.   
  3. using namespace std;  
  4.   
  5.    
  6.   
  7. class Parent  
  8.   
  9. {  
  10.   
  11. public:  
  12.   
  13.       int p;                                           // p将会被所有的子类继承,也将是二义性的根源  
  14.   
  15.    
  16.   
  17.       inline Parent()  
  18.   
  19.       {  
  20.   
  21.                p = 10;  
  22.   
  23.       }  
  24.   
  25. };  
  26.   
  27.    
  28.   
  29. class Child1 : public Parent  
  30.   
  31. {  
  32.   
  33. public:  
  34.   
  35.       int c1;  
  36.   
  37.    
  38.   
  39.       inline Child1()  
  40.   
  41.       {  
  42.   
  43.                p = 12;                           // p在子类Child1中被赋值为12  
  44.   
  45.                c1 = 12;  
  46.   
  47.       }  
  48.   
  49. };  
  50.   
  51.    
  52.   
  53. class Child2 : public Parent  
  54.   
  55. {  
  56.   
  57. public:  
  58.   
  59.       int c2;  
  60.   
  61.    
  62.   
  63.       inline Child2()  
  64.   
  65.       {  
  66.   
  67.                p = 13;                          // p在子类Child2中被赋值为13  
  68.   
  69.                c2 = 13;  
  70.   
  71.       }  
  72.   
  73. };  
  74.   
  75.    
  76.   
  77. class GrandChild : public Child1, public Child2  
  78.   
  79. {  
  80.   
  81. public:  
  82.   
  83.       int grandchild;  
  84.   
  85.    
  86.   
  87.       // p显然也存在于GrandChild中,但是到底是12,还是13呢?这就产生了二义性  
  88.   
  89.       inline GrandChild()  
  90.   
  91.       {  
  92.   
  93.                grandchild = 14;  
  94.   
  95.       }  
  96.   
  97.  };  
  98.   
  99.    
  100.   
  101. int main(void)  
  102.   
  103. {  
  104.   
  105.       GrandChild* pGC = new GrandChild();  
  106.   
  107.        
  108.   
  109.       cout << pGC->p << endl;  
  110.   
  111.    
  112.   
  113.       return 0;  
  114.   
  115. }  


 

 

上面程序是不能通过编译的,编译器输出的错误信息如下:

…: error C2385: 'GrandChild::p' is ambiguous

…: warning C4385: could be the 'p' in base 'Parent' of base 'Child1' of class 'GrandChild'

…: warning C4385: or the 'p' in base 'Parent' of base 'Child2' of class 'GrandChild'

正如编译器告诉我们的那样,GrandChild::p是模棱两可,它被Child1继承了即Child1中包含了一个Parent subobject,也被Child2继承了即Child2中也包含了一个Parent suboject,然后GrandChild又同时继承了Child1和Child2,根据“derived class中要保持base class的完整原样性原则”,因此GrandChild包含了两个ParentObject。所以当pGC->p时,编译器根本无法确定是调用Child1::p还是Child2::p,由此边产生了模棱两可的情形。怎么解决这样的问题呢?答案就是用虚继承或者叫虚基类的方式。

 

在上面的示例程序中做如下改动:

class Child1 : public Parent       ->     class Child1 :virtual public Parent

class Child2 : public Parent      ->      class Child2 :virtual public Parent

GrandChild的定义维持不变:

class GrandChild : public Child1, public Child2

 

做了上述改动后,即增加了两个 virtual关键字,再编译就不会出现ambiguous之类的错误了。这是因为加上了virtual关键字后,就可以保证Parent suboject在GrandChild中只存在一份,从而消除了ambiguity。上面修改后的程序运行结果是13,这说明Child2类的那个p起了作用,如果GrandChild的定义写成:

     class GrandChild : public Child2, public Child1

那么运行结果将是12。

 

上面的试验结果表面,在多重继承的时候,如果父类中有同名的成员变量(类似这篇文章中谈及的例子),为了防止二义性,一般要采用虚继承的方式,并且最右边的基类中的那个成员变量会出现在派生类对象中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值