菱形继承
当我们对继承有了一定了解就可以探究更复杂的继承关系,菱形继承就是一种复杂的继承。
首先先了解几个概念
单继承:一个子类只继承了一个父类。
多继承:一个子类继承了多个父类
菱形继承就是他们的继承关系形成了一个菱形,如图。
我们再通过代码才说明一个问题。
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;
}
从图中我们可以看出D对象中将A放到的了对象组成的最下面,这个A同时属于B和C,那么B和C如何去找到公共的A呢?这里是通过了B和C的两个指针,指向的一张表。这两个指针叫虚基表指针,这两个表叫虚基表。虚基表中存的偏移量。通过偏移量可以找到下面的A。
如下图
以上就是继承中比较复杂的菱形继承和虚拟继承。