菱形继承问题

来源:互联网 发布:安安电子狗软件 编辑:程序博客网 时间:2020/10/20 16:22

文章前半部分引用:http://blog.csdn.net/icerlion/article/details/4409618

考虑这种情况:

class CA{};

class CB : public CA{};

class CC : public CA{};


这时我们需要一个CD类,它需要同时继承CB和CC。

问题就出现了。

如果我们这样写:

class CD : public CB, public CC{};

 

那么我们在构造一个CD类的时候,

其结果如下:

一个孙子有两个爷爷

 

即:一个CD类中有两个CA(它的超类的对象)

这样的情况是不合理的。此时会出现模糊调用的现象。

 

如何避免这种现象呢?

虚继承就有了用武之地。

 

我们需要改写CB和CC的继承方式。

class CB : public virtuel CA{};

class CC : public virtual CA{};

 

其他无需修改。此时我们构造一个CD类的时候,

其顺序如下:

开始构造CD类,

先构造一个超类CA,然后构造CB,

在构造CC(此时不会构造CC的父类CA)

这样一来,

CD类对象中包含的CB和CC将共享同一份CA对象。

 一个孙子就只有一个爷爷

这时就不会出现模糊调用的现象了。

 

这个就是C++臭名昭著的多继承。

在JAVA中根本不会出现这种情况,

如果必须使用菱形继承的时候务必使用虚拟继承。

如果你的项目中有太多的菱形继承,

你或许应该重新考核一下你的软件工程师。

--------------------------------------------------------------------------

例子:

fun.h

[cpp] view plaincopy
  1. #ifndef FUN_H  
  2. #define FUN_H  
  3.   
  4. class A  
  5. {  
  6. public:  
  7.     int a;  
  8.     A()  
  9.     {  
  10.         a=10;  
  11.     }  
  12. };  
  13.   
  14. class B1:public A //没有使用虚继承  
  15. {  
  16. public:  
  17.     int b1;  
  18.     B1()  
  19.     {  
  20.         b1=1;  
  21.         a=11;  
  22.     }  
  23. };  
  24.   
  25. class B2:public A //没有使用虚继承  
  26. {  
  27. public:  
  28.     int b2;  
  29.     B2()  
  30.     {  
  31.         b2=2;  
  32.         a=12;  
  33.     }  
  34. };  
  35.   
  36. class C:public B1,public B2  
  37. {  
  38. public:  
  39.     int c;  
  40.     C()  
  41.     {  
  42.         c=3;  
  43.     }  
  44. };  
  45. #endif  



// main.cpp

[cpp] view plaincopy
  1. #include "fun.h"  
  2. #include <iostream>  
  3. using namespace std;  
  4.   
  5. int main()  
  6. {  
  7.     C *pc=new C();  
  8.     cout<<pc->a<<endl;  
  9.     return 0;  
  10. }  


编译不通过,提示A的数据成员a为模糊调用;

[plain] view plaincopy
  1. main.cpp: In function ‘int main()’:  
  2. main.cpp:25: error: request for member ‘a’ is ambiguous  
  3. fun.h:24: error: candidates are: int A::a  
  4. fun.h:24: error:                 int A::a  
  5. make: *** [all] 错误 1  


当将fun.h中B1、B2改为虚拟继承A之后则可编译通过;

[cpp] view plaincopy
  1. class B1:virtual public A  
  2.   
  3. class B2:virtual public A  


同时运行结果将为12,

[plain] view plaincopy
  1. root@debian6:/home/michael/cppProject/angleInheritance# make  
  2. g++ -c  main.cpp  
  3. g++ -o t main.o  
  4. rm *.o  
  5. root@debian6:/home/michael/cppProject/angleInheritance# ./t  
  6. 12  
结果12的原因是C类构造函数C()会先调用虚基类A的构造函数A(),然后再调用自身父类构造函数B1(),B2(),调用顺序是根据“class C:public B1,public B2”从左向右依次进行。


若将C的继承顺序改为 class C:public B2,public B1”后,结果则为11

[plain] view plaincopy
  1. root@debian6:/home/michael/cppProject/angleInheritance# make  
  2. g++ -c  main.cpp  
  3. g++ -o t main.o  
  4. rm *.o  
  5. root@debian6:/home/michael/cppProject/angleInheritance# ./t  
  6. 11  
原创粉丝点击