C++57个入门知识点_50 菱形继承与虚继承(C++中语法允许多重继承造成菱形继承;会造成近亲结婚的问题;可以通过虚继承的方式解决;实际项目中不多用多重继承)

上篇C++57个入门知识点_49 多重继承与组合(一个类同时具有多个类的属性的方法:多重继承或者组合;多重继承:一个类同时继承多个类;多重继承构造和析构的顺序与普通继承类似;组合:类中包含多个成员对象)介绍了多重继承及组合,实际项目中使用多重继承的情况并不多见,因为他会出现一种特殊的情况,称之为菱形继承。

1. 菱形继承的定义及使用


在C++中如果 ABC的父类,而 D又多重继承于 BC组成的继承关系很像一个菱形,我们把这种继承关系称之为 菱形继承

在这里插入图片描述

这种继承关系,天生的语法缺陷,会导致D的对象在调用A中的成员时,存在调用不明确的问题。
这就像:生物上三代以内不能结婚,否则父母致病的隐形基因可能显示在子代中,菱形继承就是一种近亲结婚现象

2. 菱形继承的问题


根据菱形继承的定义,以下代码中定义 CFurniture类作为 CSofa类和 CBed类的父类, CSofaBed继承自 CSofa类和 CBed类,此时用户通过 CSofaBed对象调用 CFurniture类的成员变量,会发生什么问题呢?

#include <iostream>

//菱形继承
//家具类
class CFurniture
{
public:
	CFurniture() {
		printf("CFurniture::CFurniture()\r\n");
		m_nFurniture = 0;
	}
	~CFurniture() {
		printf("~CFurniture()\r\n");
	}
	void use() {
		printf("sit\r\n");
	}
public:
	int m_nFurniture;
};

//虚继承
class CSofa :public CFurniture
{
public:
	CSofa() {
		m_nSofa = 1;
		printf("CSofa()\r\n");
	}
	~CSofa() {
		printf("~CSofa()\r\n");

	}
	void Sit() {
		printf("sit\r\n");
	}
public:
	int m_nSofa;

};

class CBed :public CFurniture
{
public:
	CBed() {
		m_nBed = 2;
		printf("CBed()\r\n");
	}
	~CBed() {
		printf("~CBed()\r\n");
	}
	void Sleep() {
		printf("Sleep\r\n");
	}
public:
	int m_nBed;
};

//某一个类既有沙发又有床的特点
//多重继承
class CSofaBed :public CSofa, public CBed
{
public:
	CSofaBed() {
		printf("CSofaBed()\r\n");
	}
	~CSofaBed() {
		printf("~CSofaBed()\r\n");
	}

	int m_nSofaBed = 3;
};

int main(int argc, char* argv[])
{
	//创建沙发床对象
	CSofaBed sofaBed;
	sofaBed.m_nFurniture = 1;

	return 0;
}

编译结果如下:显示对CFurniture类的成员变量的访问不明确
在这里插入图片描述
报错原因需要查看sofaBed内存结构,其父类CSofa类和CBed类中都有CFurniture类的成员变量m_nFurniture,也就造成编译器在编译sofaBed.m_nFurniture = 1;时不明确针对的是哪一个父类中变量。

上面提到的模型即为:D的对象在调用A中的成员,会发现,B、C中分别都有一个A的成员,造成一个D对象,2个A成员的对应关系。
在这里插入图片描述

  • 当然我们可以通过指定作用域的方式来明确父类中变量

以下代码中通过指定sofaBed中调用的是CSofaCBed某一类域的方式,来明确调用哪个父类内容

int main(int argc, char* argv[])
{
	//创建沙发床对象
	CSofaBed sofaBed;

	sofaBed.CSofa::m_nFurniture = 1;
	sofaBed.CBed::m_nFurniture = 1;

	return 0;
}

除了成员变量,成员函数的调用也是类似的

int main(int argc,char* argv[])
{
	//创建沙发床对象
	CSofaBed sofaBed;

	//菱形继承,CFurniture类中的成员变量继承到了两个子类中,需要加上作用域才能指明具体位置
	sofaBed.CSofa::m_nFurniture = 1;
	sofaBed.CBed::m_nFurniture = 1;

    sofaBed.use();//存在this指针调用不明确的问题
	//成员函数与成员变量一样的方式
	sofaBed.CSofa::use();
	sofaBed.CBed::use();

	return 0;
}

问题虽然解决了,按道理sofaBed只是一套家具,应该只有一份m_nFurniture变量,但是上面代码实现,不管如何去写都是具有2份变量。正是由于2份变量的存在,才会造成语法上的不明确,这是语法上菱形继承天生的缺陷。虚继承的出现就是为了打破这种近亲结婚的现象!

3.菱形继承的解决方法:虚继承,及建议


生物上三代以内不能结婚,否则父母致病的隐形基因可能显示在子代中,菱形继承就是一种近亲结婚现象。上面代码中 sofaBed的父类 CSofaCBed都继承自 CFurniture,都继承了 m_nFurniture的致病因子,因此在后代中就会造成冲突。

通过CSofaCBed增加virtual关键字实现虚继承,就可以解决近亲结婚的问题,其写法如下:

class CSofa :virtual public CFurniture{......}

class CBed :virtual public CFurniture{......}

采用虚继承之后,不管是通过B、C指向的A的成员,都是一个地址下的成员变量,即sofaBed的父类中的m_nFurniture是公有的,因此通过让子类只有一份隐形基因的方式解决了近亲结婚生病的问题。
在这里插入图片描述
同样的对成员函数的效果也是一样的

这是C++中的允许使用多重继承造成的菱形继承的缺陷,这也是实际项目中比较少用菱形继承的原因

4.学习视频地址:C++57个入门知识点_50 菱形继承与虚继承

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十月旧城

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值