条款40:明智而审慎地使用多重继承

多重继承往往会导致二义性:

class Base1
{
public:
	void func()
	{
		cout<<"base1 func"<<endl;
	}
};

class Base2
{
private:
	bool func()
	{
		cout<<"base2 func"<<endl;
		return true;
	}
};


class Derived:public Base1,public Base2
{
};

int main()
{

	Derived d;
	//d.func();二义性
	return 0;
}
也许你会奇怪,Base2中的func应该是不会被继承下来的,可是为什么在调用func时还会产生二义性呢?这是因为编译器在检查函数是否可取之前,先会判断这个函数是否是最佳匹配。此时,有两个最佳匹配,所以就会出现二义性。所以,最好是明确你要调用的是哪个基类的函数:d.Base1::func();


这还不是最可怕的情况,最可怕的是出现“钻石型多重继承”:B和C继承自A,而且D继承自B和C。此时,理论上讲,D中会有两份A的public成员(这里假定是public继承),但实际上,大多数时候,我们只希望有一份,此时只能通过虚继承来避免这种现象。
class Base
{
public:
	void print()
	{
		cout<<"base"<<endl;
	}
};

class Middle1:public Base
{

};

class Middle2:public Base
{
	
};

class Derived:public Middle1,public Middle2
{

};
此时,d.print();将会有二义性,因为他不知道自己调用的是从Middle1继承下来的print还是从Middle2继承下来的print。此时,只需要将Middle1和Middle2声明为虚继承,就会只从基类中保存一份print副本。
我们觉得,似乎所有的继承都该被声明为虚继承,但是虚继承会使派生类的大小变得更大,而且访问速度更慢。还有一点需要注意的,就是在使用虚继承之后,构造函数的调用顺序也变了:不再是派生类调用自己的基类,依次向上层调用了,而是从最高的基类开始,向下调用。
因此,不到万不得以,不要使用虚基类,在使用时,尽量避免在其中放置数据,因为它的初始化规则跟一般情况不同。


然后书中给出了一个使用的多重继承的例子:有一个接口类,我们需要实现它;恰巧我们有一个现成的类,这个类的功能跟我们要实现的类相似,但是我们需要对它的虚函数进行重写,已达到我们希望的功能,于是我们public继承了这接口,又private继承了它的实现,并对其中的某些实现重定义了。这时候,多重继承真的就派上了用场。
总的来说,多重继承可能会引起很多问题:二义性、构造、析构函数的顺序,类的大小、访问速度等等。但有时的确也会使用到它。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值