C++中的继承(三)

C++中的继承(三)

一、复杂菱形继承和菱形虚拟继承

1.单继承:一个子类只有一个直接父类时称这种继承关系为单继承
在这里插入图片描述
2.多继承:一个子类有两个或两个以上的直接父类时,称这种继承关系为多继承。
在这里插入图片描述
3.菱形继承:为多继承的一种特殊情况
在这里插入图片描述

二、菱形继承的问题:

1.先看一段代码

class Person
{
public :
string _name ; // 姓名
};
class Student : public Person
{
protected :
int _num ; //学号
};
class Teacher : public Person
{
protected :
int _id ; // 职工编号
};
class Assistant : public Student, public Teacher
{
protected :
string _majorCourse ; // 主修课程
};
void Test ()
{
// 这样会有二义性无法明确知道访问的是哪一个
Assistant a ;
a._name = "peter";
// 需要显示指定访问哪个父类的成员可以解决二义性问题,但是数据冗余问题无法解决
a.Student::_name = "xxx";
a.Teacher::_name = "yyy";
}

通过上面的代码就可以发现,菱形继承的问题是容易出现二义性,即person类中有一个成员变量name,student类和teacher类都继承person类,那么student和teacher都有person类中的成员变量name,那么,Assistant类继承student和teacher类,就说明类中既有student中的name,也有teacher类中的name,此时如果在Assistant类中访问name成员变量,就会出现二义性,不知道访问那个name,此时就得加类名来访问避免二义兴。

三、解决菱形继承:

1.采用菱形虚拟继承来解决菱形继承的二义性:

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 = "peter";
}

2.解决的原理:

用下面的代码来研究菱形虚拟继承的原理:

class A
{
public:
int _a;
};
// class B : public A
class B : virtual public A
{
public:
int _b;
};
// class C : public A
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对象放到派生类D的最下面,B和C取4个字节用来存放虚基表指针,虚基表指针指向虚基表,虚基表中存放偏移量,虚基表中第一个存放想对自己的偏移量,第二个存放相对_a的偏移量,通过偏移量来找到_a,这样使得A类中的数据只存一份,就解决了菱形继承的二义性

四、注意

1.注意菱形虚拟继承的sizeof大小;
2.看下面代码选择
A. p1 == p2 == p3
B. p1 < p2 < p3
C. p1 == p3 != p2
D. p1 != p2 != p3

class Base1 {
public:
int _b1;
};
class Base2 {
public:
int _b2;
};
class Derive : public Base1, public Base2 {
public:
int _d;
};
int main(){
Derive d;
Base1* p1 = &d;
Base2* p2 = &d;
Derive* p3 = &d;
return 0;
}

答案是C
在这里插入图片描述

发布了49 篇原创文章 · 获赞 15 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/wolfGuiDao/article/details/103847296