标签搜索

目 录CONTENT

文章目录

C++中的继承(三).md

小小城
2021-08-22 / 0 评论 / 0 点赞 / 11 阅读 / 1,829 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-05-02,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

C++中的继承(三)

@[toc]

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

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
在这里插入图片描述

0

评论区