为什么要使用继承?[已关闭]

我知道这个问题以前讨论过,但似乎总是假设继承至少有时比组合更可取。我想挑战这个假设,希望能得到一些理解。

我的问题是这样的:既然你可以用对象组合完成任何经典继承,既然经典继承经常被滥用[1],既然对象组合可以让你灵活地更改委托对象运行时,那么你为什么要使用经典继承呢?

我可以理解为什么你会建议在一些语言(如Java和C++)中进行继承,这些语言不提供方便的委派语法。在这些语言中,您可以使用继承来节省大量键入,只要这样做没有明显不正确。但是像Objective C和Ruby这样的其他语言既提供了经典的继承,也为委派提供了非常方便的语法。据我所知,Go 编程语言是唯一一种认为经典继承比它的价值更麻烦的语言,它只支持代码重用的委派。

另一种表达我问题是:即使你知道经典继承对于实现某个模型来说并不是不正确的,那么这个理由是否足以使用它而不是组合?

[1]许多人使用经典继承来实现多态性,而不是让他们的类实现接口。继承的目的是代码重用,而不是多态性。此外,有些人使用继承来模拟他们对“is-a”关系的直观理解,这通常是有问题的

更新

我只是想澄清一下,当我谈论继承时,我到底是什么意思:

我说的是一种继承,即类从部分或完全实现的基类继承。我不是在谈论从纯抽象基类继承,这与实现接口是一回事,我记录在案并不反对。

更新 2

我理解继承是实现多态性的唯一途径,C++。在这种情况下,很明显为什么你必须使用它。因此,我的问题仅限于Java或Ruby等语言,它们提供了实现多态性的不同方法(分别是接口和鸭子类型)。


答案 1

[注意:这个问题最初被标记为与语言无关。基于此,这个答案被写成相当与语言无关,所以它讨论了继承,因为它被广泛应用于各种语言,如Smalltalk,C++和Object Pascal。此后,它被重新标记为专门针对Java。Java在将a和an定义为两个完全独立的东西方面是不同的。从特定于Java的角度来看,继承的目的是代码重用而不是多态性的想法是合理的,但从与语言无关的角度来看,这显然是错误的。如果你只关心Java,这可能不是最好的答案。classinterface

继承的目的是代码重用,而不是多态性。

这是你的根本错误。几乎完全相反的情况。(公共)继承的主要目的是对相关类之间的关系进行建模。多态性是其中很大一部分。

如果使用得当,继承不是重用现有代码。相反,它是关于现有代码使用。也就是说,如果您有可以使用现有基类的现有代码,那么当您从该现有基类派生新类时,其他代码现在也可以自动使用您的新派生类。

可以使用继承进行代码重用,但是当您这样做时,通常应该是私有继承而不是公共继承。如果您使用的语言很好地支持委派,那么您很少有理由使用私有继承。OTOH,私有继承确实支持一些委派(通常)不支持的东西。特别是,即使在这种情况下,多态性显然是次要问题,但它仍然可以是一个问题 - 即,通过私有继承,您可以从几乎符合您需求的基类开始,并且(假设它允许它)覆盖不太正确的部分。

通过委派,您唯一真正的选择是完全按照现有类的原样使用现有类。如果它不能完全满足您的要求,您唯一真正的选择是完全忽略该功能,并从头开始重新实现它。在某些情况下,这不是损失,但在其他情况下,这是非常可观的。如果基类的其他部分使用多态函数,则私有继承允许您仅重写多态函数,而其他部分将使用重写的函数。使用委派,您无法轻松插入新功能,因此现有基类的其他部分将使用您重写的内容。


答案 2

使用继承的主要原因不是作为一种组合形式 - 它是这样你可以得到多态行为。如果你不需要多态性,你可能不应该使用继承,至少在C++。