2

我正在研究多重继承的概念(自从我愤怒地编写 C++ 代码以来已经快 10 年了,并且只是在学术上对这个概念感兴趣)。我在维基百科上找到了这个参考

他们列出的对 MI 的一个批评是“不能从一个类中显式地多次继承”。我对这个声明感到困惑,并且不能 100% 确定这是指什么。

当然,类继承描述了一个类的结构,并且从同一个类多次继承只会重复同一个类契约,所以我看不出它会给批评带来什么好处。显式继承会假设类函数和属性的多个实例吗?

我想了解这种批评指的是什么,以及为什么它隐含地不适用于启用多重继承的语言。

4

6 回答 6

6

这称为钻石问题。大多数允许 MI 的现代语言对此都有解决方案。

简而言之,你有这个类树:

class A { public int f = 0; };

class B extends A { f = 1; };

class C extends A { f = 2; };

class D extends B, C {};

Df 会打印什么?如果你给 Df 赋值,它应该存储在哪里?两个字段 B(A).f 和 C(A).f 应该合并为一个还是应该分开?如果在 B 和 C 中覆盖 A 的方法 x,Dx() 应该做什么?两个都叫?按什么顺序?返回值呢?

于 2009-02-10T12:49:44.483 回答
1

同样,我已经 5 年多没有愤怒地编写 C++ 了,现在已经切换到 C#。我真的不记得我是否经常使用多重继承,但我不会错过它,特别是因为我可以对接口进行编码并且这些天我更多地使用组合。

但是,在有史以来最好的 OO 书籍中- 可能 ;) - Betrand Meyer 很好地捍卫了多重继承。他在这里也做了类似的防御。

于 2009-02-10T11:52:33.700 回答
1

我认为它们的意思是类 Car 不能从它的四个轮子继承(例如,继承类 Wheel 的四倍)。[参见同一维基百科页面上的 C++ 节]

但是,我认为这种“省略”实际上是一个积极的特征,因为继承是为了表达子类型,而没有“单一类型的多个子类型”。这种“显式多重继承”不会比简单的组合更好。

于 2009-02-10T11:53:16.957 回答
1

我认为问题在于那篇特定的维基百科文章。它包含不止一个尴尬或模糊的陈述,例如这些珠宝:

Tcl 允许多个父类——它们的序列会影响类成员的名称解析。

然而,这六种语言允许类从多个接口继承,重新创建了一些提到的问题,同时避免了其他问题。

坦率地说,我不知道作者在您问题中的这句话是什么意思。这只是一篇写得不好的文章中含糊不清的另一个例子,恕我直言。

于 2009-02-10T12:22:34.267 回答
1

多重继承是面向对象编程的 GOTO。它的出现是因为早期 OOP 语言(C++ 等)采用的方法。它在右手中效果很好,但在其他大部分时间里它会让人困惑。

OOP 的主要目标之一是重用行为。原来这是一个嵌合体。在某些情况下很有用,但在其他情况下,我们真正感兴趣的是定义对象如何交互。看看设计模式中有多少模式使用接口而不是继承。

实现接口,然后是显式聚合是执行与多重继承相同的事情的更清晰、更易于维护的方式。几乎所有的 OOP 都有一些定义接口的方法,几乎​​所有的 OOP 都可以将对象聚合在一起。然而,OOP 以微妙的不同方式处理多重继承引发的问题(钻石问题等)。就像 GOTO 一样,当您使用多重继承查看代码时,不清楚发生了什么。然而,就像 GOTO 一样,它在不同的情况下很有用。

对我来说,使用任何困难的语言结构的主要考虑因素是我是否必须长期维护应用程序。如果我这样做了,那么即使现在需要更多的编程,我也会选择最清晰、更容易维护的方法。像其他一切一样,这是一个判断电话。请注意,在大多数情况下,我们最终会坚持使用我们开发的程序比我们想象的要长得多。

于 2009-02-10T13:31:05.757 回答
0

实际上,在 C++ 中,一个类可以从同一个类多次继承:

A类{};

B类:公共A();

C类:公共A();

类 D:公共 B,公共 C {};

现在 D 以 A 的两个副本结束。这通常被认为是“一个坏主意”,C++ 提供了虚拟继承来控制它。

于 2009-02-10T12:00:03.090 回答