什么是菱形继承?
首先,我们看一下单继承,以及多继承是什么?
单继承:一个子类只有一个直接父类时称这个继承关系为单继承
多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承
菱形继承:菱形继承是多继承的一种特殊情况
菱形继承的问题:从下面的对象成员模型构造,可以看出菱形继承有数据冗余和二义性的问题。在Assistant的对象中Person成员会有两份。
虚拟继承
虚拟继承可以解决菱形继承的二义性和数据冗余的问题,如上模型图所示的继承关系,在Student和Teacher继承Person时使用虚拟继承,即可解决问题。需要注意的是,虚拟继承不要在其它地方去使用。
class Person
{
public:
string _name;//姓名
};
class Student :virtual public Person
{
protected:
int _num;//学号
};
class Teacher :virtual public Person
{
protected:
int _id;//职工编号
};
class Assistant :public Student, public Teacher
{
protected:
string _majorCourse;//主修课程
};
void Test()
{
Assistant a;
a._name = "xiaozhang";
}
虚拟继承解决数据冗余和二义性的原理
我们给出一个简化的菱形继承体系,借助内存窗口观察对象成员的模型。
class A
{
public:
int _a;
};
class B :virtual public A
{
public:
int _b;
};
class C :virtual public A
{
public:
int _c;
};
class D :public B, public C
{
public:
int _d;
};
int main()
{
D d;
d.B::_a = 1;
d.C::_a = 2;
d._b = 3;
d._c = 4;
d._d = 5;
return 0;
}
首先,我们不使用virtual虚拟继承时,菱形继承的内存对象成员模型如下:(可以看到数据冗余)
下图是菱形虚拟继承的内存对象成员模型:可以看出D对象中将A放到了对象组成的最下面,这个A同时属于B和C,那么B和C如何找到公共的A呢?这里是通过B和C的两个指针,指向的一张表,这两个指针叫虚基表指针,这两个表叫虚基表。虚基表中存的偏移量。通过偏移量可以拿到A.
下面是Person关系菱形虚拟继承的原理解释: