菱形继承和虚拟继承

菱形继承

      当我们对继承有了一定了解就可以探究更复杂的继承关系,菱形继承就是一种复杂的继承。

首先先了解几个概念

单继承:一个子类只继承了一个父类。

菱形继承和虚拟继承_第1张图片

多继承:一个子类继承了多个父类

菱形继承和虚拟继承_第2张图片

菱形继承就是他们的继承关系形成了一个菱形,如图。

菱形继承和虚拟继承_第3张图片

我们再通过代码才说明一个问题。

class Person
{
public:
	string _name = "djh";
};

class Student : public Person
{
public:
	int _number = 99;// 学号
};
class Teacher : public Person
{
public:
	int _job = 101;//工号
};

class Assistant : public Student, public Teacher
{
public:
	int _age = 18;//年龄
};
int main()
{
	Assistant a;
	a._name = "DJH"
}

Student和Teacher这两个类都继承了Person这个基类,然后Assistant又继承了Student和Teacher。他们都继承了_name这个成员,然后再被Assistant继承,那么这个_name是哪个_name呢?根本说不清。

菱形继承的问题:从下面的对象成员模型构造,可以看出菱形继承有数据冗余和二义性的问题。在Assistant的对象中Person成员会有两份

我们可以通过显示访问的方法解决数据二义性的问题,但是数据冗余的问题却无法得到根本的解决。

int main()
{
	Assistant a;
	a.Student::_name = "DJH";
	a.Teacher::_name = "djh";
	return 0;
}

这时候就出现了虚拟继承。

 

虚拟继承

虚拟继承可以解决菱形继承的二义性和数据冗余的问题。如上面的继承关系,在Student和Teacher的继承Person时使用虚拟继承,即可解决问题。需要注意的是,虚拟继承不要在其他地方去使用。

class Person
{
public:
	string _name = "djh";
};

class Student : virtual public Person
{
public:
	int _number = 99;// 学号
};
class Teacher : virtual public Person
{
public:
	int _job = 101;//工号
};

class Assistant : public Student, public Teacher
{
public:
	int _age = 18;//年龄
};

继承的时候加上关键字代表虚拟继承就可以了,那么他是如何解决数据冗余和二义性的问题的呢?

 

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;
}

菱形继承和虚拟继承_第4张图片

从图中我们可以看出D对象中将A放到的了对象组成的最下面,这个A同时属于B和C,那么B和C如何去找到公共的A呢?这里是通过了B和C的两个指针,指向的一张表。这两个指针叫虚基表指针,这两个表叫虚基表。虚基表中存的偏移量。通过偏移量可以找到下面的A。

如下图

菱形继承和虚拟继承_第5张图片

以上就是继承中比较复杂的菱形继承和虚拟继承。

 

你可能感兴趣的:(菱形继承和虚拟继承)