分析菱形继承

C++中的继承体系,有单继承、多继承、还有复杂的菱形继承,今天我们只讨论菱形继承,以及菱形继承存在的问题,最后我们针对问题给出解决方案。

(1)什么是菱形继承?
顾名思义,菱形继承就是,几个类的继承关系呈菱形状。为此,我们举例解释:
题目:有4个类,Person类、Student类、Teacher类、Assistant类,Student、Teacher继承Person,Assistant继承Student、Teacher。
具体继承关系,以及菱形继承对象模型如下图:



由以上两个图和各个类中的成员,我们会发现菱形继承存在一定的问题:
(1)当创建一个D的对象d时,由于D同时继承了B,C,而B,C都有从A继承过来
的成员_name,即我们要对d中的_name操作时,无法判断是B,C谁的成员,这个问题叫做
菱形继承的二义性
(2)假如说,A中的某一个成员被B,C继承之后,就想当成同一个变量使用,那么
就会有同一个变量才B,C存了2份的情况,这就造成了空间浪费,这个问题就
称为菱形继承的数据冗余

解决二义性的问题倒是有个简单的办法,就是在访问具体变量的时候,前面加上作用域解析符(::),但是要想同时解决二义性,数据冗余,我们提出一个另外一个方法,即虚继承;虚继承就是在有争议的变量的类的继承体系中,继承方式关键字前面加关键字virtual;本例中,就是Student、Teacher虚继承Person

那么,虚继承是怎么解决以上问题呢?
为了简单明了解释这个问题,我们再举个例子:4个类,A类,B类,C类,D类,继承关系如下图:


以上几个类继承的代码实现如下:

  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. class A  
  5. {  
  6. public:  
  7.     int a;  
  8. };  
  9.   
  10. class B: public A  
  11. {  
  12. public:  
  13.     int b;  
  14. };  
  15.   
  16. class C: public A  
  17. {  
  18. public:  
  19.     int c;  
  20. };  
  21.   
  22. class D:public B,public C  
  23. {  
  24. public:  
  25.     int d;  
  26. };  
  27.   
  28. void test()  
  29. {  
  30.     D d;  
  31.     d.B::a=1;  
  32.     d.C::a=2;  
  33.     d.b=3;  
  34.     d.c=4;  
  35.     d.d=5;  
  36.     cout<<"q"<<endl;  
  37. }  
  38.   
  39. int main()  
  40. {  
  41.     test();  
  42.     return 0;  
  43. }  
        通过对比正常的菱形继承,加了虚继承之后D对象d内存情况,我们发现经过虚继承之后,类A中之前那个有争议的成员变量,不在分别自B,C中各存一份,而是在B,C中

都存了一份神秘的地址,在地址里存了这个成员变量的相对偏移量,通过这个偏移量即可找到这个公共的成员变量a;另外,虚继承之后,给公共的成员变量赋值,最后一个有效;以下是验证结果图(图1为没有虚继承的d的内存;图2为有虚继承的d的内存)

         

图1


图2  


全部评论

相关推荐

点赞 评论 收藏
分享
害怕一个人的小黄鸭胖乎乎:笑死了,没有技术大牛,招一堆应届生,不到半年,代码就成屎山了
点赞 评论 收藏
分享
去B座二楼砸水泥地:不过也可以理解,这种应该没参加过秋招
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务