携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第7天,点击查看活动详情
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;
}
错误提示:
结论:
当菱形继承,两个父类拥有相同的数据,需要加以作用域区分。
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 请按任意键继续. . .
结论:
这份数据我们知道,只有一份就可以,菱形继承导致数据有两份,资源浪费
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 请按任意键继续. . .
利用虚继承可以解决这个问题:
语法:继承之前加上关键字virtual。
超级明星类称为虚基类
虚继承之后这份数据只有一个了。
底层怎么来的?
vbptr
v-virtual
b-base
ptr-pointer
虚基类指针
virtual sheep指针会指向他的虚基类表vbtableSheep,这个表记录了一个数据:偏移量,0+8指向m_age
结论:
虚继承并不是继承了两份数据,而是继承了两份指针,两份指针又会通过偏移量指向唯一的数据