1006继承07菱形继承以及虚继承

68 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第7天,点击查看活动详情

1 菱形继承简述

两个派生类继承同一个基类

又有某个类同时继承者两个派生类

这种继承被称为菱形继承,或者钻石继承

2 举例说明:超级明星刘德华即是歌手又是演员,歌手和演员都有当下的年龄

问题:

  1. 歌手继承了超级明星的数据,演员同样继承了超级明星的数据,当刘德华使用数据时,就会产生二义性。

  2. 刘德华继承自超级明星的数据继承了两份,其实我们应该清楚,这份数据我们只需要一份就可以。

#include<iostream>
using namespace std;
class Superstar
{
public:
	int age;
};

class Actor : public Superstar {};
class Songer : public Superstar {};
class Liudehua : public Actor,public Songer{};
//私有继承
void test()
{
	Liudehua s;
	s.age = 40;
}
int main() {

	test();

	system("pause");

	return 0;
}

错误提示: 1660100061956.png

结论:

当菱形继承,两个父类拥有相同的数据,需要加以作用域区分。

void test()
{
	Liudehua s;
	s.Actor::age = 40;
	s.Songer::age = 20;
	cout << "Actor-age = " << s.Actor::age << " Songer-age = " << s.Songer::age << endl;
}

输出:

Actor-age = 40 Songer-age = 20 请按任意键继续. . .

1660100561746.png 结论:

这份数据我们知道,只有一份就可以,菱形继承导致数据有两份,资源浪费

3 解决办法

  • 菱形继承带来的主要问题是子类继承两份相同的数据,导致资源浪费以及毫无意义
  • 利用虚继承可以解决菱形继承问题
class Actor : virtual public Superstar {};
class Songer : virtual public Superstar {};
class Liudehua : public Actor,public Songer{};
//私有继承
void test()
{
	Liudehua s;
	s.Actor::age = 40;
	s.Songer::age = 20;
	cout << "Actor-age = " << s.Actor::age << " Songer-age = " << s.Songer::age << endl;
}

输出:

Actor-age = 20 Songer-age = 20 请按任意键继续. . .

1660100928067.png

利用虚继承可以解决这个问题:

语法:继承之前加上关键字virtual。

超级明星类称为虚基类

虚继承之后这份数据只有一个了。

底层怎么来的?

vbptr

v-virtual

b-base

ptr-pointer

虚基类指针

virtual sheep指针会指向他的虚基类表vbtableSheep,这个表记录了一个数据:偏移量,0+8指向m_age

结论:

虚继承并不是继承了两份数据,而是继承了两份指针,两份指针又会通过偏移量指向唯一的数据