C++ 学习之菱形继承

菱形继承概念:

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

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

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

典型的菱形继承案例:

C++ 学习之菱形继承
菱形继承问题:

  1. 羊继承了动物的数据,驼同样继承了动物的数据,当*使用数据时,就会产生二义性。
  2. *继承自动物的数据继承了两份,其实我们应该清楚,这份数据我们只需要一份就可以。
第一版代码(未使用虚继承)
#include<iostream>
#include<string>
using namespace std;

class animal//父类
{
public:
	int m_age;
};

class sheep:public animal   //sheep继承了animal 类
{
};

class tuo:public animal  //tuo也继承了animal 类
{
};

class sheeptuo :public sheep, public tuo  //sheeptuo 又多继承了sheep 和 tuo 类
{
};

void main()
{
	sheeptuo s;
	//s.m_age;//不明确

	cout << "sheeptuo所占空间:" << sizeof(sheeptuo) << endl; //8  因为继承了两个age

	s.sheep::m_age = 200;
	s.tuo::m_age = 300;
	
	cout << "sheep中age:" << s.sheep::m_age << endl;
	cout << "tuo中age:" << s.tuo::m_age << endl;
}
第二版代码(使用虚继承)
#include<iostream>
#include<string>
using namespace std;

class animal//父类
{
public:
	int m_age;
};

//继承前加virtual关键字后,变为虚继承
//此时公共的父类Animal称为虚基类
class sheep:virtual public animal   //sheep继承了animal 类,虚继承
{
};

class tuo:virtual public animal  //tuo也继承了animal 类,虚继承
{
};

class sheeptuo :public sheep, public tuo  //sheeptuo 又多继承了sheep 和 tuo 类
{
};

void main()
{
	sheeptuo s;

	//12字节 因为继承了一个age,使用虚继承又增加了两个指针,两个指针都指向age这个变量;所有的age都是同一个,都是在对同一个数据操作
	cout << "sheeptuo所占空间:" << sizeof(sheeptuo) << endl; 

	s.sheep::m_age = 200;
	s.tuo::m_age = 300;  //以最后的赋值数据为准,之前的都被覆盖
	
	cout << "sheep中age:" << s.sheep::m_age << endl;
	cout << "tuo中age:" << s.tuo::m_age << endl;
	
	cout << "sheeptuo中age:" << s.m_age << endl;
}

可以看一下内存模型分布

C++ 学习之菱形继承
C++ 学习之菱形继承
增加了两个vbptr指针, v:virtual b:base ptr:pointer
vbptr指向vbtable虚基类表,第一个vbptr指向 sheep的虚基类表,偏移量为8,偏移量加8之后就找到了age这个变量;第二个vbptr指向 tuo的虚基类表,偏移量为4,偏移量加4之后就找到了age这个变量;他们指向的都是同一个变量。

总结

  • 菱形继承带来的主要问题是子类继承两份相同的数据,导致资源浪费以及毫无意义
  • 利用虚继承可以解决菱形继承问题
上一篇:设计模式——原型模式


下一篇:两个小时实现C++简单的通讯录管理系统