条款40:明智而审慎地使用多重继承
1、关于MI 和 SI的两个观点
MI 多重继承,SI单一继承。C++开发者分为两派,一派认为如果单一继承是好的,那么多重继承一定是更好的,即,支持多重继承。但是另一派认为,单一继承是好的,但是应该尽量少用多重继承,即不支持多重继承。
2、多重继承可能引发的问题:名称歧义
(1)引发歧义举例
clas BorrowableItem{
public:
void checkOut();
……
};
class ElectronicGadgent{
private:
bool checkOut() const;
……
};
class MP3Player: public BorrowableItem, public ElectronicGadget
{
……
};
MP3Player mp;
mp.checkOut();//歧义,调用哪个checkOut?
(2)为什么引发歧义?
虽然上面两个函数一个是public
,一个是private
,但还是有歧义。
这与C++用来解析(resolving)重载函数调用的规则相符:在看到是否有个函数可取用之前,C++首先确认这个函数对此调用是最佳匹配。上面两个checkOut
有相同匹配度。为了解决歧义,必须指明调用哪一个base class
内的函数
(3)解决名称歧义的方法
调用时写清楚调用的函数版本,符合编译器规则就能够被正确调用。
mp.BorrowableItem::checkOut(); //成功调用
mp.ElectronicGadgent::checkOut(); //该版本是private的,会导致编译错误
3、钻石性多重继承
(1)什么是钻石型多重继承?
举例:
(2)钻石型多重继承面临的问题:subclass
应该拥有几份baseclass
的成员?
- 从逻辑上来讲,应该拥有一份,例如上述描述的是文件,那么文件应该只有一个名字。
- 从继承关系上来讲,应该拥有两份。
(3)C++支持的解决钻石型多重继承问题的两个方案
C++对上述两种角度都支持,缺省情况下,C++支持的是拥有两份。
如果你需要的设计是拥有一份,那么可以通过:另base class virtual
类,派生类由public继承,改为采用virtual public
继承 这两个点来实现此需求。(C++标准程序库中确实含有一个这样的继承体系。)
4、关于pubilc virtual
继承
virtual
的成本:
virtual
继承的class
比non-virtual
继承的class体积要大、访问成员变量的速度也相比较慢,此种细节因编译器不同而异。virtual
继承的初始化及赋值情况复杂,且不直观。
5、对于virtual base classes
的忠告
- 如非迫不得已,不使用
virtual
继承。 - 必须使用virtual 继承时,
virtual base classes
类中尽可能不要放置成员变量,以避免初始化为题。(即:定义成virtual
接口类。)
总结:
多重继承只是面向对象的一个工具而已。和单一继承比较,它比较复杂,也难以理解,所以如果有一个单一继承方案和一个多重继承方案,那么单一继承方案比较受欢迎。但是如果通过多重继承可以完成任务,而且最简洁、最易维护、最合理,那么就不用怕使用它。
多重继承的确有正当用途。其中一个情节设计public
继承某个Interface class
和private
继承某个协助实现的class
。