多继承出现的菱形继承问题

问题:存在多继承特性的语言,在进行类的多继承时就会出现菱形继承的问题。

1、菱形继承案例:

例如下述CPP代码:

c 复制代码
class GrandParent_A
{
public:
	std::string a;
	GrandParent_A()
	{
		a = "GrandParent_A";
		std::cout << "GrandParent_A Constructed" << std::endl;
	}
	//static void Print()
	//{
	//	std::cout << "is GrandParent_A Function" << std::endl;
	//}
	void Print()
	{
		std::cout << "is GrandParent_A Function" << std::endl;
	}
	virtual void PrintVirtual()
	{
		std::cout << "is GrandParent_A virtual Function" << std::endl;
	}

	virtual void PrintPureVirtual() = 0;
};

class Parent_B :public GrandParent_A
{
public:
	std::string b;
	Parent_B()
	{
		b = "Parent_B";
		std::cout << "Parent_B Constructed" << std::endl;
	}
	virtual void PrintVirtual()
	{
		std::cout << "is Parent_B virtual Function" << std::endl;
	}
	void PrintPureVirtual() override {
		std::cout << "is Parent_B Purevirtual Function" << std::endl;

	}
};

class Parent_C :public GrandParent_A
{
public:
	std::string c;
	Parent_C()
	{
		c = "Parent_C";
		std::cout << "Parent_C Constructed" << std::endl;
	}
	virtual void PrintVirtual()
	{
		std::cout << "is Parent_C virtual Function" << std::endl;
	}
	void PrintPureVirtual() override {
		std::cout << "is Parent_C Purevirtual Function" << std::endl;
	}
};

class GrandSon_D :public Parent_B, public Parent_C
{
public:
	std::string d;
	GrandSon_D() {
		d = "GrandSon_D";
		std::cout << "GrandSon_D Constructed" << std::endl;
	}
	//virtual	void PrintVirtual()
	//{
	//	std::cout << "is GrandSon_D override Function" << std::endl;
	//}

};

类Parent_B,类Parent_C 分别继承类GrandParent_A,然后GrandSon_D同时继承了Parent_B,Parent_C。这就形成了菱形继承,这时候发现GrandParent_A会进行两次构造将内容复制两份。

如下图,查看输出发现GrandParent_A进行了两次构造,

GrandParent_A进行了两次构造

再查看内存地址发现存在两个GrandParent_A字符串内容。

所以这是后想输出GrandParent_A的成员会出现 "不明确"警告。

c 复制代码
	GrandSon_D d;
	//std::cout << d.a << std::endl; //"GrandSon Da"不明确
	std::cout << d.Parent_B::a << std::endl;
	std::cout << d.Parent_C::a << std::endl;
	//d.Print(); //"GrandSonD::Print"不明确
	d.Parent_C::Print();
	d.Parent_B::Print();
	//d.PrintVirtual(); //"GrandSonD::PrintVirtual不明确
	d.Parent_C::PrintVirtual();
	d.Parent_B::PrintVirtual();
	//d.PrintPureVirtual(); //"GrandSonD:PrintPureVirtual"不明确
	d.Parent_C::PrintPureVirtual();
	d.Parent_B::PrintPureVirtual();

2、使用虚继承解决菱形继承问题:

对中间基类进行虚继承(继承时加上Virutal关键字),如下:

c 复制代码
#pragma region 虚继承
class Parent_VirtualB : virtual public GrandParent_A
{
public:
	std::string b;
	Parent_VirtualB()
	{
		b = "Parent_VirtualB";
		std::cout << "Parent_VirtualB Constructed" << std::endl;
	}
	//virtual void PrintVirtual()
	//{
	//	std::cout << "is Parent_VirtualB virtual Function" << std::endl;
	//}
	void PrintPureVirtual() override {
		std::cout << "is Parent_VirtualB Purevirtual Function" << std::endl;

	}
};

class Parent_VirutalC :virtual public GrandParent_A
{
public:
	std::string c;
	Parent_VirutalC()
	{
		c = "Parent_VirutalC";
		std::cout << "Parent_VirutalC Constructed" << std::endl;
	}
	//virtual void PrintVirtual()
	//{
	//	std::cout << "is Parent_VirutalC virtual Function" << std::endl;
	//}
	void PrintPureVirtual() override {
		std::cout << "is Parent_VirutalC Purevirtual Function" << std::endl;
	}
};

class GranSon_VirtualD :public Parent_VirtualB, public Parent_VirutalC
{

public:
	std::string d;
	GranSon_VirtualD() {
		d = "GranSon_VirtualD";
		std::cout << "GranSon_VirtualD Constructed" << std::endl;
	}
	void PrintPureVirtual() override {
		std::cout << "is GranSon_VirtualD Purevirtual Function" << std::endl;
	}
};
#pragma endregion

这时候就只会出现一次构造,内存里也只会有一份GrandParent_A内容,也避免了1里不明确的问题出现

3、为了避免多继承问题出现,要么多使用virtual,要么使用接口多实现来代替。

c 复制代码
#pragma region 接口实现
class IGrandP_A
{
public:
	virtual void Print() = 0;
	IGrandP_A()
	{
		std::cout << "IGrandP_A Constructed" << std::endl;
	}
};

class IParent_B :public IGrandP_A
{
public:
	//virtual void Print() = 0;
	virtual void Print()
	{
		std::cout << "is IParent_B function" << std::endl;
	}
	IParent_B()
	{
		std::cout << "IParent_B Constructed" << std::endl;

	}
};

class IParent_C :public IGrandP_A
{
public:
	//virtual void Print() = 0;
	virtual void Print()
	{
		std::cout << "is IParent_C function" << std::endl;
	}
	IParent_C()
	{
		std::cout << "IParent_C Constructed" << std::endl;

	}
};

class GrandSon_ID :public IParent_B, public IParent_C
{
public:
	void Print()
	{
		std::cout << "is GrandSon_ID function" << std::endl;
	}
	GrandSon_ID()
	{
		std::cout << "GrandSon_ID Constructed" << std::endl;

	}
};

#pragma endregion

因为接口没有实现,子类实现是就属于子类了。而且没有字段。

其他没有多继承的语言如C#可能就是考虑到这个问题来,使用接口来避免。

参考链接:

arduino 复制代码
https://zhuanlan.zhihu.com/p/365223471
arduino 复制代码
https://zhuanlan.zhihu.com/p/342271992
arduino 复制代码
https://zhuanlan.zhihu.com/p/651947545
相关推荐
熊小猿17 小时前
在 Spring Boot 项目中使用分页插件的两种常见方式
java·spring boot·后端
paopaokaka_luck17 小时前
基于SpringBoot+Vue的助农扶贫平台(AI问答、WebSocket实时聊天、快递物流API、协同过滤算法、Echarts图形化分析、分享链接到微博)
java·vue.js·spring boot·后端·websocket·spring
小蒜学长19 小时前
springboot酒店客房管理系统设计与实现(代码+数据库+LW)
java·数据库·spring boot·后端
橙子家19 小时前
Serilog 日志库简单实践(一):文件系统 Sinks(.net8)
后端
Yeats_Liao20 小时前
Go Web 编程快速入门 13 - 部署与运维:Docker容器化、Kubernetes编排与CI/CD
运维·前端·后端·golang
Yeats_Liao20 小时前
Go Web 编程快速入门 14 - 性能优化与最佳实践:Go应用性能分析、内存管理、并发编程最佳实践
前端·后端·性能优化·golang
七夜zippoe21 小时前
仓颉语言核心特性深度解析——现代编程范式的集大成者
开发语言·后端·鸿蒙·鸿蒙系统·仓颉
软件架构师-叶秋21 小时前
spring boot入门篇之开发环境搭建
java·spring boot·后端
QX_hao1 天前
【Go】--接口(interface)
开发语言·后端·golang
superman超哥1 天前
仓颉语言中正则表达式引擎的深度剖析与实践
开发语言·后端·仓颉