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类,继承关系如下图:
以上几个类继承的代码实现如下:
#include <iostream>
using namespace std;
class A
{
public:
int a;
};
class B: public A
{
public:
int b;
};
class C: public A
{
public:
int c;
};
class D:public B,public C
{
public:
int d;
};
void test()
{
D d;
d.B::a=1;
d.C::a=2;
d.b=3;
d.c=4;
d.d=5;
cout<<"q"<<endl;
}
int main()
{
test();
return 0;
}
通过对比正常的菱形继承,加了虚继承之后D对象d内存情况,我们发现经过虚继承之后,类A中之前那个有争议的成员变量,不在分别自B,C中各存一份,而是在B,C中
都存了一份神秘的地址,在地址里存了这个成员变量的相对偏移量,通过这个偏移量即可找到这个公共的成员变量a;另外,虚继承之后,给公共的成员变量赋值,最后一个有效;以下是验证结果图(图1为没有虚继承的d的内存;图2为有虚继承的d的内存)
图1 图2