当前位置:  开发笔记 > 编程语言 > 正文

多重继承的确切问题是什么?

如何解决《多重继承的确切问题是什么?》经验,为你挑选了7个好方法。

我可以看到人们一直在询问是否应该在下一版本的C#或Java中包含多重继承.有幸拥有这种能力的C++人说,这就像给某人一条绳子最终自我吊死.

多重继承有什么问题?有没有具体的样品?



1> benjismith..:

最明显的问题是功能覆盖.

假设有两个类A和B,它们都定义了一个方法"doSomething".现在定义一个继承自A和B的第三个类C,但是不要覆盖"doSomething"方法.

当编译器播种此代码时......

C c = new C();
c.doSomething();

...应该使用哪种方法实现?在没有任何进一步澄清的情况下,编译器无法解决模糊性问题.

除了重写之外,多重继承的另一个大问题是内存中物理对象的布局.

像C++,Java和C#这样的语言为每种类型的对象创建一个固定的基于地址的布局.像这样的东西:

class A:
    at offset 0 ... "abc" ... 4 byte int field
    at offset 4 ... "xyz" ... 8 byte double field
    at offset 12 ... "speak" ... 4 byte function pointer

class B:
    at offset 0 ... "foo" ... 2 byte short field
    at offset 2 ... 2 bytes of alignment padding
    at offset 4 ... "bar" ... 4 byte array pointer
    at offset 8 ... "baz" ... 4 byte function pointer

当编译器生成机器代码(或字节码)时,它使用这些数字偏移来访问每个方法或字段.

多重继承使它非常棘手.

如果C类继承自A和B,则编译器必须决定是以AB顺序还是以BA顺序布局数据.

但现在想象一下你在B对象上调用方法.它真的只是一个B吗?或者它实际上是一个C对象通过其B接口多态调用?根据对象的实际身份,物理布局将不同,并且无法知道要在呼叫站点调用的函数的偏移量.

处理这种系统的方法是抛弃固定布局方法,允许尝试调用函数或访问其字段之前查询每个对象的布局.

所以......长话短说......编译器作者支持多重继承是一件痛苦的事.因此,当像Guido van Rossum这样的人设计python时,或者当Anders Hejlsberg设计c#时,他们知道支持多重继承将使编译器实现变得更加复杂,并且可能他们认为这种好处不值得花费.


嗯,Python支持MI
这些都不是很有说服力的论点 - 在大多数语言中固定布局的东西都不是很棘手; 在C++中它很棘手,因为内存不是不透明的,因此你可能会遇到指针算术假设的困难.在class*definitions*是静态的语言中(如在java,C#和C++中),可以禁止多个继承名称冲突编译时间(无论如何C#都使用接口执行此操作!).
"_最明显的问题是函数覆盖._"这与函数重写无关.这是一个简单的歧义问题.
OP只是想了解这些问题,我在没有亲自编辑此事的情况下解释了这些问题.我只是说语言设计者和编译器实现者"大概不认为这样做的好处是值得的".
这个答案有一些关于Guido和Python的错误信息,因为Python支持MI._"我决定,只要我支持继承,我不妨支持一个简单的多重继承版本."_ - Guido van Rossum http://python-history.blogspot.com/2009/02 /adding-support-for-user-defined-classes.html - 另外,模糊度解析在编译器中相当常见(变量可以是块到局部,局部到函数,局部到封闭函数,对象成员,类成员,全局等等) .),我不知道额外的范围会如何产生影响.

2> 小智..:

你们提到的问题并不是很难解决.事实上,例如埃菲尔完美地做到了!(并且不引入任意选择或其他)

例如,如果你从A和B继承,两者都有方法foo(),那么你当然不希望你的类C继承A和B的任意选择.你必须重新定义foo所以它很清楚会是什么如果调用c.foo()或者你必须重命名C中的一个方法,则使用它(它可能变为bar())

另外我认为多重继承通常非常有用.如果你看一下埃菲尔的图书馆,你会发现它已经遍布整个地方,而且当我不得不回到Java编程时,我已经错过了这个功能.


我同意.人们讨厌MI的主要原因与JavaScript或静态类型相同:大多数人只使用过非常糟糕的实现 - 或者使用它非常糟糕.用C++判断MI就像用PHP判断OOP或者用Pintos判断汽车一样.
埃菲尔是正确的.或至少错误.
@Guvante MI在任何语言中唯一的问题是糟糕的程序员认为他们可以阅读教程并突然知道一种语言.
此外,当白痴不正确地使用它时,只会从MI发生错误.
@JörgWMittag在C++中MI有什么问题?
@curiousguy:MI引入了另一组令人担忧的复杂问题,就像许多C++的"特性"一样.仅仅因为它是明确的并不容易使用或调试.删除这个链,因为它脱离主题,你无论如何都要把它吹掉.
我认为语言功能不仅仅是减少编码时间.它们还涉及增加语言的表达能力和提高性能.

3> J Francis..:

钻石问题:

当两个类B和C继承自A,而D类继承自B和C时出现歧义.如果A中的方法B和C已重写,而D不覆盖它,那么哪个版本的D继承的方法:B的那个,还是C的?

...由于这种情况下类继承图的形状,它被称为"钻石问题".在这种情况下,A级位于顶部,B和C分别位于其下方,D将两者连接在一起形成菱形......


它有一个称为虚拟继承的解决方案.如果你做错了,这只是一个问题.
@IanGoldby:足够公平.我的观点是Java和.NET的实施者在决定不支持广义MI时不仅"懒惰"; 支持广义MI将阻止他们的框架维护各种公理,这些公理的有效性对于许多用户而言比MI更有用.
@supercat也许,但是这样的问题在很大程度上是理论上的,并且在任何情况下都可以由编译器发出信号.重要的是要注意你要解决的问题,然后使用最好的工具,忽视那些宁愿不关心自己理解"为什么?"的人的教条.

4> KeithB..:

多重继承是经常不使用的东西之一,可能被滥用,但有时需要.

我从来没有理解不添加功能,只是因为它可能被滥用,没有好的选择.接口不是多重继承的替代方案.首先,它们不允许您强制执行先决条件或后置条件.就像任何其他工具一样,您需要知道何时使用它以及如何使用它.


@Yttrill因为接口不能有方法实现.你把'断言'放在哪里?

5> tloach..:

假设你有对象A和B都由C继承.A和B都实现了foo()而C没有.我叫C.foo().选择哪种实施方案?还有其他问题,但这类事情很重要.


@tloach - 如果C不能解决歧义,编译器可以检测到此错误并返回编译时错误.

6> Mendelt..:

多重继承的主要问题很好地总结了tloach的例子.当从实现相同函数或字段的多个基类继承时,编译器必须决定要继承哪个实现.

当从多个继承自同一基类的类继承时,这会变得更糟.(钻石继承,如果你绘制继承树,你得到钻石形状)

对于编译器来说,这些问题并不是真正的问题.但是编译器必须在这里做出的选择是相当随意的,这使代码更不直观.

我发现在做好OO设计时我从不需要多重继承.在我需要它的情况下,我通常发现我一直在使用继承来重用功能,而继承只适用于"is-a"关系.

还有其他技术,如mixin,可以解决相同的问题,并且没有多重继承所具有的问题.


编译后的*不需要做出任意选择 - 它可以简单地输出错误.在C#中,什么类型的`([.. bool ..]?"test":1)`?
在C++中,编译器永远不会做出这样的任意选择:定义一个编译器需要做出任意选择的类是一个错误.

7> Turing Compl..:

我不认为钻石问题是一个问题,我会认为这是诡辩,没有别的.

从我的角度来看,最糟糕的问题是多重继承是RAD - 受害者和声称自己是开发人员的人,但实际上他们仍然处于半知识状态(充其量).

就个人而言,如果我最终可以在Windows窗体中做这样的事情(这不是正确的代码,但它应该给你的想法),我会很高兴:

public sealed class CustomerEditView : Form, MVCView

这是我没有多重继承的主要问题.您可以使用接口执行类似的操作,但是我称之为"s***代码",这是一个令人痛苦的重复性问题,例如,您必须在每个类中编写以获取数据上下文.

在我看来,对于现代语言中的任何重复代码,应该绝对没有必要,也不是最轻微的.


@Turing完成:没有任何代码重复:这是个好主意,但它是不正确的,也是不可能的.有大量的使用模式,我们希望将常见的抽象模式抽象到库中,但是抽象所有这些模式是很费力的,因为即使我们能够记住所有名称的语义负载太高.你想要的是一个很好的平衡.不要忘记重复是什么赋予事物结构(模式意味着冗余).
推荐阅读
可爱的天使keven_464
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有