《Effective C++》读书笔记 条款40:明智而审慎地使用多重继承

多重继承的存在有其合理性,但是在使用多重继承的时候也要注意存在的问题

1.一个派生类可能从多个基类继承相同的名称(函数、typedef等等),这会导致较多的歧义

例子:

#include<iostream>

using namespace std;

class base1
{
public:
	void fun1();
	void fun2();
};

class base2
{
public:
	void fun1();
	void fun3();
};

class Derived :public base1, public base2
{

};

int main()
{
	Derived d;
	//d.fun1(); //error C2385 : 对“fun1”的访问不明确
		    // 可能是“fun1”(位于基“base1”中)
		    // 也可能是“fun1”(位于基“base2”中)
	return 0;
}

Derived public继承自base1和base2,由于两个基类中存在同名的函数fun1,所以在调用fun1时就出现了歧义,不知道调用的是哪一个,我们可以这样调用

d.base1::fun1();

所以多重继承可能会导致歧义,就算base的fun1()改为private,也不能阻止这种错误。因为C++首先是确认函数的最佳匹配而后才检验其可取性。在基类调用时发现两个相同匹配程度的函数,产生歧义。

2.多重继承导致菱形继承问题

如果B,C继承自A,D又继承自B,C(都是public继承),如上图,

#include<iostream>

using namespace std;

class A
{
public:
	void fun();
private:
	int b;
};
class B:public A
{
private:
	int b1;
	
};

class C :public A
{
private:
	int b2;
};

class D :public B, public C
{

};

int main()
{
	D d;
	d.fun(); //error C2385 : 对“fun”的访问不明确
	        //可能是“fun”(位于基“A”中)
		       // 也可能是“fun”(位于基“A”中)
	return 0;
}

运行胆码会发现调用fun函数产生歧义,错误信息是两个一模一样的fun位于基A中,原因是这种继承导致D从B和C中继承了A,解决办法就是让B和C virtual public继承自A,这虽然可以解决D中存在两份A的问题。

class B:virtual public A
{
private:
	int b1;
	
};

class C :virtual public A
{
private:
	int b2;
};

class D :public B, public C
{

};

但是virtual继承会增加对象的体积,是成员访问速度变慢等等,并且virtual 基类的初始化由继承体系中的最底层负责,这里A的初始化由D负责。

尽量不要使用虚基类,如果必须使用,不要在虚基类中放置数据。

多重继承也有其存在的合理性,用public继承接口,用private继承协助实现,这种多重继承的组合书上写了一个例子。所以说多重继承可以使用但是要明智而审慎地使用它

请记住:

1.多重继承比单一继承复杂。它可能导致新的歧义性,以及对virtual继承的需要。

2.virtual继承会增加大小、速度、初始化(及赋值)复杂度等等成本。如果virtual base classes 不带任何数据,将是最具有实用价值的情况。

3.多重继承的确有正当用途。其中一个情节涉及“public继承某个Interface class”和“private继承某个协助实现的class”的两相组合。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值