真的需要继承吗?

Joe*_*eda 32 oop inheritance

我必须承认我有点像OOP怀疑论者.面向对象的不良教学和实验经验无济于事.所以我转变成了Visual Basic中的狂热信徒(经典之作!).

然后有一天我发现C++已经改变了,现在有了STL和模板.我真的很喜欢!使语言有用.然后另一天MS决定对VB进行面部手术,我真的很讨厌无端更改的最终结果(使用"end while"而不是"wend"会让我成为一个更好的开发者?为什么不放下"next"for"结束了",为什么呢?为什么强迫getter和setter一起?等等?加上我发现无用的Java特性(例如继承,以及分层框架的概念).

现在,几年后,我发现自己在问这个哲学问题:遗产真的需要吗?

四人一组说我们应该支持对象组合而不是继承.在考虑它之后,我找不到你可以用继承做的事情,你不能用对象聚合和接口做.所以我想知道,为什么我们甚至在第一时间拥有它?

有任何想法吗?我很想看到一个例子,说明继承器肯定需要在哪里,或者使用继承而不是组合+接口可以导致更简单和更容易修改的设计.在以前的工作中,我发现如果你需要更改基类,你还需要修改几乎所有的派生类,因为它们取决于父行为.如果你使基类'方法虚拟...那么没有太多的代码共享发生:(

另外,当我最终创建自己的编程语言(我发现大多数开发人员共享的长期未满足的愿望)时,我认为添加继承没有任何意义......

小智 33

真的很简短的答案:不需要继承,因为只需要字节代码.但显然,字节代码或汇编不是编写程序的实际方法.OOP不是编程的唯一范例.但是,我离题了.

我在21世纪初进入计算机科学专业,当时继承(是a),作文(有a)和接口(做a)是在平等的基础上进行的.因此,我使用非常少的继承,因为它通常更适合于组合.这是强调的,因为许多教授因为滥用继承而看到了错误的代码(以及你所描述的内容).

无论是否使用继承创建语言,您是否可以创建一种编程语言来防止不良习惯和糟糕的设计决策?


Men*_*elt 22

我认为要求实际需要继承的情况稍微缺少一点.您可以通过使用接口和一些组合来伪造继承.这并不意味着继承是无用的.你可以在汇编代码中用VB6做一些额外的打字,这并不意味着VB6没用.

我通常只是开始使用界面.有时我注意到我实际上想要继承行为.这通常意味着我需要一个基类.就这么简单.


S.L*_*ott 14

继承定义了"Is-A"关系.

class Point( object ):
    # some set of features: attributes, methods, etc.

class PointWithMass( Point ):
    # An additional feature: mass.
Run Code Online (Sandbox Code Playgroud)

上面,我使用继承来正式声明PointWithMass是一个Point.

处理P1PointWithMass和Point的对象有几种方法.这是两个.

  1. 有一个从PointWithMass对象p1到一些Point对象的引用p1-friend.该p1-friend具有Point的属性.当p1需要参与Point类似行为时,需要将工作委托给其朋友.

  2. 依靠语言继承来确保所有功能Point都适用于我的PointWithMass对象,p1.当p1需要参与类似Point行为时,它已经一个Point对象,可以做需要做的事情.

我宁愿不管理浮动的额外对象,以确保所有超类特征都是子类对象的一部分.我宁愿继承,以确保每个子类都是它自己的类的实例,并且也是所有超类的实例.

编辑.

对于静态类型的语言,有一个奖励.当我依靠语言来处理这个问题时,PointWithMass可以在任何Point预期的地方使用.

对于非常模糊的滥用继承,请阅读C++奇怪的"通过私有继承构成"的泥潭.请参阅创建继承而不创建子类型关系的任何合理示例?对此进行进一步讨论.它混合了遗产和构成; 它似乎没有为结果代码增加清晰度或精度; 它只适用于C++.

  • “is-a”关系很难建立正确。曾经读过一篇关于类“Set”继承自类“Bag”的文章,因为“集合是一个只接受每种类型之一的包”。然后,基类中的一个微小更改(在堆中分配对象而不是在构造函数中分配堆栈)导致使用 Set 的测试应用程序崩溃。 (2认同)
  • 我不同意。很多人不明白为什么 Set 不是*包,也不是 Square 是 Rectangle,不管他们有多少共同的属性和行为。这不是一个糟糕的实现问题 - 这是 Liskov 原则,这在实践中很困难,这使得继承变得困难。 (2认同)

Bil*_*ard 12

GoF(和许多其他人)建议您只赞成组合而不是继承.如果你有一个具有非常大的API的类,并且你只想添加非常少量的方法,只留下基本实现,我会发现使用组合是不合适的.您必须重新实现封装类的所有公共方法才能返回它们的值.当你可以继承所有这些行为并花时间专注于新方法时,这是浪费时间(程序员和CPU).

所以,回答你的问题,不,你不是绝对需要继承.然而,在许多情况下,它是正确的设计选择.


idi*_*dak 11

继承的问题在于它混淆了子类型(断言is-a关系)和代码重用的问题(例如,私有继承仅用于重用).

所以,不,这是一个我们不需要的重载词.我更喜欢子类型(使用'implements'关键字)和import(有点像Ruby在类定义中做)

  • 我无法表达得更清楚了!我在继承方面遇到的很多问题是因为开发人员使用它来获得“自由”重用,而不是断言“is-a”关系。语言应该将这两个问题分开! (2认同)

Mar*_*gel 7

继承允许我将一大堆簿记推送到编译器上,因为它为我提供了对象层次结构的多态行为,否则我将不得不创建和维护自己.无论一个银弹OOP有多好,总会有一些你希望采用某种行为的情况,因为这样做才有意义.最终,这就是OOP的重点:它使某类问题更容易解决.