600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > 读书笔记《Effective C++》条款40:明智而审慎地使用多重继承

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

时间:2024-01-04 19:56:43

相关推荐

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

一旦涉及多重继承,C++社群便分为两个基本阵营。一派认为如果单一继承是好的,多重继承一定更好。另一派主张,单一继承是好的,但多重继承不值得使用。

最先需要认清的一件事是,当用到多重继承,程序有可能从一个以上的base class继承相同名称(如函数、typedef等等),那会导致较多的歧义。例如:

class BorrowableItem {public:void checkOut();};class ElectronGadget {private:bool checkOut() const;};class MP3Player : public BorrowableItem, public ElectronGadget {};MP3Player mp;mp.checkOut();//歧义:调用的是哪个checkOut?

注意此例中对checkOut的调用是有歧义的,即使两个函数之中只有一个可取用(BorrowableItem内的checkOut是public,ElectronicGadget内的却是private)。这与C++用来解析重载函数调用的规则相符:在看到是否有个函数可取用之前,C++首先确认这个函数对此调用之言是最佳匹配。找出最佳匹配函数后才检验其可取性。本例中的两个checkOut函数有相同的匹配程度,没有所谓最佳匹配。因此ElectronicGadget::checkOut的可取用性也就从未被编译器审查。

为了解决这个歧义,必须明确指出要调用哪一个base class内的函数:

mp.BorrowableItem::checkOut();

多重继承的意思是继承一个以上的base class,但这些base class并不常在继承体系中又有更高级的base class,那会导致要命的“钻石型多重继承”:

class File {};class InputFile : public File {};class OutputFile : public File {};class IOFile : public InputFile, public OutputFile {};

任何时候如果有一个继承体系而其中某个base class和某个derived class之间有一条以上的相同路线,就必须面对这样一个问题:是否打算让base class内的成员变量经由每一条路径被复制?假设File class有个成员变量fileName,那么IOFile内该有多少笔这个名称的数据呢?从某个角度说,IOFile从其每一个base class继承一份,所以其对象内应该有两份fileName成员变量。但从另一个角度说,IOFile对象只该有一个文件名称,所以它继承自两个base class而来的fileName不该重复。

C++对这两个方案都支持——虽然其缺省做法是执行复制。如果那不是你想要的,你必须令那个带有此数据的class(也就是File class)成为一个virtual base class。为了这样做,必须令所有直接继承自它的class采用“virtual继承”:

class File {};class InputFile : virtual public File {};class OutputFile : virtual public File {};class IOFile : public InputFile, public OutputFile {};

从正确行为的观点看,public继承应该总是virtual。但是为了避免继承得来的成员变量重复,编译器必须提供若干幕后工作,而其后果是:使用virtual继承的那些class所产生的对象往往比使用non-virtual继承的class体积大,访问virtual base class的成员变量时,也比访问non-virtual base class的成员变量速度慢。种种细节因编译器不同而异,但基本重点很清楚:你得为virtual继承付出代价。

virtual继承的成本还包括其他方面。支配“virtual base class初始化”的规则比其non-virtual base的情况远为复杂且不直观。virtual base的初始化责任是有继承体系中的最低层class负责。

忠告很简单:第一,非必要不使用virtual base。平常请使用non-virtual继承。第二,如果你必须使用virtual base class,尽可能避免在其中放置数据。这么一来就不需要担心这些class身上的初始化(和赋值)所带来的诡异事情了。Java和.Net的Interface值得注意,它在许多方面兼容于C++的virtual base class,而且也不允许含有任何数据。

要点:

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

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

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

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。