C++编程批评系列继承的本质

C++编程批评系列继承的本质,第1张

C++编程批评系列继承的本质,第2张

Eiffel和C++都提供了多重继承机制。但是Java没有,因为它认为多重继承会导致很多问题。但是Java提供了一个接口作为替代机制,类似于Objective C中的协议,Sun声称接口可以提供多重继承所能提供的所有特性。

孙说的“多重继承会带来很多问题”是对的,尤其是在C++中。那些看似使用多重继承比单一继承简单的理由,现在被证明毫无意义。例如,如何为继承自两个类的同名数据项制定策略?他们互相兼容吗?如果是,是否应该将它们合并为一个实体?如果不兼容,应该如何区分?……这样的清单可以列很久。

Java的接口机制也可以用来实现多重继承,但它也有一个重要的区别(与C++相比):继承中的接口必须是抽象的。因为没有接口的实现,所以排除了从不同实现中选择的可能性。Java允许在接口中声明带有常量的字段。当需要多重继承时,将它们合并为一个实体,不会导致二义性。但是当这些常数有不同的值时会发生什么呢?

由于Java不支持多重继承,所以我们不能像在C++和Eiffel中那样使用mixin。Mixing是一个特性,可以把不同类的不同非抽象函数放在一起,形成一个新的复杂的类。例如,我们可能想从不同的源代码中导入一些实用函数。但是我们也可以用组合代替继承来达到同样的效果,所以这不会构成对Java的重要攻击。

Eiffel没有引入单独的接口机制来解决多重继承问题。

有些人可能认为单继承比多继承更优雅。这是一个很特别的观点。

BETA [Madsen 93]属于认为“多重继承不优雅”的那一类:“BETA中没有多重继承,这主要是由于(对于多重继承)缺乏深刻的理论理解,并且目前的提议(对于多重继承)在技术上非常复杂”。他们引用了Flavors(一种可以将类混合在一起的语言)作为证据。与Madsen相比,Flavors中的多重继承与其顺序有关,即从(A,B)继承不同于从(B,A)继承。

Ada95是另一种不支持多重继承的语言。Ada95支持单一继承,它被称为标记类型扩展。

另一些人认为多重继承可以为一些特殊模型中的问题提供优雅的解决方案,因此值得付出努力。虽然上面列出的关于多重继承的问题清单并不完善,但仍然说明了与多重继承相关的问题是可以被系统识别的,一旦问题被确认,就可以优雅地解决。当[Sakkinen 92]对多重遗传的研究达到一个很深的层次时,它提出了上述定义。

Eiffel采用的方法是多重继承会引起一些有趣的、有挑战性的问题,然后优雅地解决。程序员需要做出的所有决定都被限制在类的继承子句中。它包括使用重命名来确保许多同名的继承特征最终将成为不同名称的特征,新的导出策略:未定义和未定义,以及选择以消除歧义。在任何情况下,编译器都会为我们完成这一切。为了使语义清晰,程序员对选择使用fork还是join有完全的控制权。

与Eiffel相比,C++具有不同的消歧机制。在Eiffel中,在renames子句中,特性必须有不同的名称。在C++中,可以使用域解析运算符“::”来区分成员。Eiffel方法的优点是消除了语句中的歧义。Eiffel的继承子句比C++复杂得多,但它的代码更简单、更稳定、更灵活。这就是声明方法优于操作符方法的地方。在C++中,每当我们遇到多个成员之间的歧义时,我们必须在代码中使用域解析运算符。这会使代码变得混乱,并影响其可扩展性。如果其他地方的更改会影响到歧义,我们可能需要在每个可能出现歧义的地方更改现有代码。

根据[Stroustrup 94]中的第12.8节,ANSI委员会考虑使用重命名,但这一提议被委员会的一名成员阻止,他坚持要求委员会的其他成员花两周时间来思考这个问题。12.8节给出的例子说明了如何在不重命名的情况下获得相同的效果。问题是,如果让那些专家花两周时间去思考如何实现,那么留给我们的空空间还有多少?

域解析运算符不仅用于消除多重继承导致的歧义。因为设计良好的语言可以避免歧义,所以域解析操作符是一种丑陋而复杂的实现技术。

在C++中,“如何声明多重继承中的双亲”是一个非常复杂的问题。它影响构造函数的调用顺序,在程序员真的想从子类变成超类的时候也会产生问题。然而,我们也可以称之为糟糕的编程风格。

C++和Eiffel的另一个区别在于直接重复继承。在Eiffel中,
B类继承A,A端但是
B类:public A,public A { };
但不被C++识别。

位律师回复
DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
白度搜_经验知识百科全书 » C++编程批评系列继承的本质

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情