分享
 
 
 

More Exceptional C++中文版试读(继承与多态)

王朝c/c++·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

[Herb Sutter 的名作More Exceptional C++中文版即将出版。作为本书译者,我很高兴将本书推荐给大家。征得华中科技大学出版社同意,我将公开部分译稿,敬请大家批评指正。]

继承与多态

不来点继承和多态,面向对象将会怎样?

尽管继承常被滥用,但它还是一种很重要的工具——这包括多继承。特别是,当你生活在现实世界中时,你会发现,你经常需要将不同供货商提供的程序库结合起来使用,此时,多继承便凸显它的价值。本章向你展示,在结合使用不同供货商提供的“基于继承”的程序库时,应当如何避免连体双婴(Siamese Twin)问题。此外,本章还示范了许多合理(以及一些不合理地)使用纯虚函数的方式,以及如何编写多继承的替代方案、如何对使用继承关系的用户施加控制。

条款24:为什么要使用多继承?

难度:6

一些语言,包括SQL99标准,还在为“是否应该支持单继承或多继承”的问题大伤脑筋。本条款邀请您讨论这一主题。

1. 什么是多继承(MI,即multiple inheritance)?在C++中引入MI带来了哪些额外的可能性和复杂性?

2. MI究竟有必要吗?如果必要,尽可能多地列举出它的使用场合,并论证为什么应该将MI加入到语言中;如果不必要,请论证为什么单继承(SI)(并且,可能结合Java风格的接口)可以取代多继承、甚至比它更出色,以及为什么不应该将MI加入到语言中。

解答

1. 什么是多继承(MI,即multiple inheritance)?在C++中引入MI带来了哪些额外的可能性和复杂性?

非常简要地回答:MI指的是从多个(多于一个)直接基类(direct class)继承的能力。

例如:

class Derived : public Base1, private Base2

{

//...

};

在C++中引入MI所带来的可能性是:一个类的同一个(直接或间接)基类(base class)可能会不只一次地作为它的基础类(ancestor)出现。这里有一个简单的例子,即那个经典的钻石形状的继承图,如图4所示。

这里,B两次作为D的间接基类(indirect class)出现,一次是通过C1,另一次则是通过C2。

这种情况下,就很有必要引入C++的另一个特性:虚拟继承。现在的问题是:程序员希望D拥有基类B的一个子对象还是两个?如果答案是一个,B就应该是一个虚拟基类,图4就成为了可怕的死亡钻石。如果答案是两个,B就应该是一个普通(非虚拟)基类。

最后,虚拟基类的主要复杂性在于:它们必须通过最底层的派生类(most-derived class)直接初始化。关于这一点的详细介绍,以及MI其它方面的知识,请参阅[stroustrup00],或[Meyers97]条款43。

B

D

C1

C2

图4:可怕的死亡钻石(如果D从B虚拟继承)

设计准则

避免多继承自多个“非protocol类”。(protocol类是一种抽象基类(abstract base class),或简称ABC,它完全由纯虚函数组成,没有数据成员。)

2. MI究竟必要吗?

简短的回答是:只要程序可以用汇编语言(或更低级的语言)来写,就不能说某种特性绝对“必要”。然而,正如大多数人不会去用简单的C编写自己的虚函数机制一样,在某些场合下,没有MI会让你大费周章。

正因为如此,我们现在才有了这一被称为MI的神奇特性。但问题是——或者,至少前面的问题应该换为——MI是个好东西吗?1

简而言之,的确有人认为MI是个坏主意,因而无论如何都应该避免它。这不对。是的,如果你在使用MI时有欠考虑,它的确会招致不必要的耦合性和复杂性。然而,任何一种被误用的继承都是这样(参见Exceptional C++ [Sutter00]条款24),但我相信,大家不会就此认为继承不是个好东西。还有,是的,在完全不使用MI的情况下,任何程序都可以写出来,但你也得知道,在完全不使用继承的情况下,任何程序也都可以写出来。实际上,任何程序都可以用汇编语言来写。但这并不是说用汇编语言来写程序就一定是个好主意,相反,你甚至不愿意去做那样的事。

2.如果必要,尽可能多地列举出它的使用场合,并论证为什么应该将MI加入到语言中;如果不必要,请论证为什么单继承(SI)(并且,可能结合Java风格的接口)可以取代多继承、甚至比它更出色,以及为什么不应该将MI加入到语言中。

那么,什么时候使用MI才算合适?简而言之,只有在每一个继承单独取出来看都合适的时候,这样的MI才算合适。Exceptional C++条款24提供了一个相当详尽的列表,说明了什么时候该使用继承。在现实世界中,MI的应用大多逃不出以下三类。

1. 结合使用程序模块或程序库。之所以首先提出这一点有一个理由,我将在后面说明。很多类被设计为基类——即,在使用时你得从它继承。这很自然地带来一个问题:如果你想写一个类,它用到了两个程序库,但每个程序库都要求你从它的某个类继承,这时候你该怎么办?

__________________

1. 一定程度上,本条款的主题启发自1998年6月SQL标准会议上发生的事件,在那次会议中,多继承被从ANSI SQL99标准草案中删除了。(如果说得远一点的话,你们当中如果有人对数据库感兴趣,就会知道,在SQL4中MI又以修订形式重新恢复了。)当时之所以那样做,主要是因为所提出的多继承规范存在技术上的困难,并且是为了想和Java这些不真正支持多继承的语言看齐。另外,仅仅是坐在那儿听人们在那样一个相对太迟的时间里争论多继承的优缺点,这本身就让人觉得有趣。在C++世界中,自这种语言形成以来,我们很少做这种事;这让我回忆起几年前(或比这更近的时期)新闻组上广泛展开的激烈争论,我会忍不住自言自语地念出一些标题,譬如:“MI是罪恶!!!”

在面对这种情况时,你一般无法通过修改程序库代码来避免某个继承。因为,它可能是从第三方供货商购买的程序库,或者,可能是你的公司里另一个项目组开发的模块。无论哪种情况,你不但不能修改代码,你甚至可能没有代码!如果是这样,MI就是必要的;没有其它(自然的)方法可以帮助你去做你必须做的事;此时,使用MI完全合理。

在实践中我发现,知道如何运用MI来结合使用供应商提供的程序库,这是每一个C++程序员必须具备的素质。无论你是否经常运用它,你绝对应该知道它并理解它。

2. Protocol类(interface类)。在C++中,MI最合适、最安全的应用是定义protocol 类——即,完全由纯虚函数构成的类。由于这种基类没有数据成员,MI臭名昭著的复杂性就得以完全避免。

有趣的是,有的语言(或模型)通过非继承机制来支持这种MI。Java和COM就是两个例子。严格来说,Java有多继承,但它将实现(implementation)的继承仅限于单继承。一个Java类可以实现多个“接口”,这种接口非常类似C++中没有数据成员的纯抽象基类。COM本身没有继承的概念(虽然在用C++来写COM对象时,这是一种常用的实现技术),但它同样也有“接口组合(composition of inerfaces)”的思想,COM接口类似Java接口和C++模板的结合。

3. 易于(多态)使用。有了继承,在接受基类对象的任何代码中,我们就都可以使用派生对象,这是一项威力强大的功能。在某些场合,如果同一个派生对象可以代替数种基类对象使用,那将会很有用处,这正是MI大显身手的地方。关于这一点有一个好例子,请参阅[Stroustrup00]14.2.2节,那里演示了一个基于MI的设计,用以构造异常类(exception class);在那个设计中,最底层的派生异常类可能和多个直接基类具有多态式的Is-A关系。

注意,第3点在很大程度上与第1、2点重叠。在实施另两点之一时,同时、并出于相同的理由运用第3点,往往很有用处。

还要考虑到另一点,不要忘记:有时候,单纯从两个不同的基类继承并没有必要,相反,我们要让每一个继承都有不同的理由。“多态的LSP Is-A 公有继承”并非唯一故事(译注:参见条款23);使用继承还有很多其它可能的原因。例如,一个类可能需要从一个基类A私有继承,以获得对类A的保护成员的访问权,同时,它还要从另一个基类B公有继承,以多态地实现类B的某个虚函数。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有