c++ 多重继承歧义及其解决办法

  关于c++中多重继承该不该使用的争论不是我们关注的问题,但是现实世界很多模型确实是多重继承类别。和单一继承相比,它比较复杂,也不太好理解,而且多基派生可能会引起二义性。下面我们就说说多重继承可能的二义性和解决办法。

       先看看没有共同基类的多基派生如何引起二义性。这种继承大致如图所示

这时候有个问题就是假如两个基类有同名的成员,编译器就无法知道要访问哪一个类的成员了,解决的方法就是加上作用域限定符,准确告诉编译器这个成员属于哪个类中的。用一个非常简单的例子代码演示下

[cpp]  view plain copy
  1. #include <iostream>  
  2.   
  3. using namespace std;  
  4.   
  5. class Base1 {  
  6. public:  
  7.     int i;  
  8. };  
  9.   
  10. class Base2 {  
  11. public:  
  12.     int i;  
  13. };  
  14.   
  15.   
  16. class Derived : public Base1, public Base2 {  
  17.   
  18. };  
  19.   
  20. int main() {  
  21.   
  22.     Derived d;  
  23.       
  24.     //下面这样的用法就会产生错误,编译器不知道i到底属于哪个基类  
  25.     //d.i = 1;  
  26.       
  27.     //加上类名限定符解决  
  28.     d.Base1::i = 1;  
  29.     d.Base2::i = 2;  
  30.   
  31.     system("pause");  
  32.   
  33.     return 0;  
  34. }  
        还有一个多基派生的情况就是含有共同基类(所谓的菱形继承)。

        类似于这种继承,由于Base1和Base2都继承Base,那Base中的成员会被拷贝到两个派生类中,这时候Derived又同时继承Base1和Base2,要是使用基类的成员,就是出现二义性,编译器无法准确知道成员到底属于谁。这种歧义的解决方法是继承的时候将继承自共同基类声明为virtual公有继承。这就是虚基类,这样引用中就只有一份基类的成员拷贝了。还是一个非常简单的例子

[cpp]  view plain copy
  1. #include <iostream>  
  2.   
  3. using namespace std;  
  4.   
  5. class Base {  
  6. public:  
  7.     int i;  
  8. };  
  9.   
  10. class Base1 : virtual public Base {  
  11. public:  
  12.     int j;  
  13. };  
  14.   
  15. class Base2 : virtual public Base {  
  16. public:  
  17.     int k;  
  18. };  
  19.   
  20.   
  21. class Derived : public Base1, public Base2 {  
  22. public:  
  23.     int sum;  
  24. };  
  25.   
  26. int main() {  
  27.   
  28.     Derived d;  
  29.       
  30.     d.i = 1;  
  31.     d.j = 2;  
  32.     d.k = 3;  
  33.   
  34.     d.sum = d.i + d.j + d.k;  
  35.     cout << d.sum << endl;  
  36.       
  37.   
  38.     system("pause");  
  39.   
  40.     return 0;  
  41. }  
        那到底是如何实现的呢,先看看有共同基类派生时,不使用virtual的派生类大小,代码及运行结果看图

        可以看出来,派生类Derived包含了Base1中的一个int 变量和Base1继承自Base中的一个int 变量,同样也包含了Base2中的一个int 变量和Base2继承自Base中的一个int 变量,所以Derived含有4个int变量,32位机器上正好是16个字节。

        在看看使用虚基类的情况,看图吧

        这种情况的对象内存布局大概是这样


        Base1中应该含有一个指向Base对象4字节虚指针和自己的的一个int变量4字节,就是8字节,同样的原理Base2也应该是8字节,派生类Derived应该是20字节=两个基类的16字节+共同基类4字节。


        多重继承要比单一继承复杂,可能会出现二义性。所以在Java语言中使用接口代替了多重继承。在c++中多重继承主要用于接口继承,接口继承仅仅是在一个派生类中加入了成员函数的声明,貌似Java就是这样的,但是c++并不支持这种做法,因为在c++中所有的继承都是实现继承,但是可以模拟实现,首先声明一个接口类,类中只有声明,没有成员数据和函数体,而且除了虚析构函数外,其余的函数都是纯虚函数,然后从这个接口类派生一个子类并实现基类中声明的函数体。关于实现继承、接口继承和可视继承会在以后有空写文章来介绍下。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值