关于c ++:继承还是组合:依靠“is-a”和“has-a”?

Inheritance or composition: Rely on “is-a” and “has-a”?

当我设计类并且必须在继承和组合之间进行选择时,我通常使用经验法则:如果关系是"is-a"-使用继承,如果关系是"has-a"-使用组合。

总是对的吗?

谢谢您。


不,"是"并不总是导致继承。一个很好的例子是一个正方形和一个矩形之间的关系。正方形是一个矩形,但是设计从矩形类继承正方形类的代码是不好的。

我的建议是加强你的"is a/has a"启发式与liskov替代原则。要检查继承关系是否符合Liskov替换原则,请询问基类的客户机是否可以在不知道它在子类上操作的情况下对该子类进行操作。当然,必须保留子类的所有属性。

在正方形/矩形示例中,我们必须询问矩形的客户机是否可以在不知道它是正方形的情况下对正方形进行操作。客户机必须知道的是,它在一个矩形上操作。下面的函数演示一个客户端,它假定设置矩形的宽度使高度保持不变。

1
2
3
4
5
6
void g(Rectangle& r)
{
    r.SetWidth(5);
    r.SetHeight(4);
    assert(r.GetWidth() * r.GetHeight()) == 20);
}

对于一个矩形,这个假设是正确的,但是对于一个正方形,这个假设是不正确的。因此,函数不能在一个正方形上操作,因此继承关系违反了Liskov替换原理。(顺便说一下,这个例子来自一个死链接。其他例子)


是没有的。

行啦,可能是模糊的。这还没被一些漂亮的孩子帮助城市学院的面向对象的编程实例,从早期的天:面向对象的类是一个员工的经理是一个人。

这件事你必须记住的是:传承传承encapsulation冰休息。传承是一个分散的零售。我们的所有品种的写在这个主题。

《pithiest路和冰吗

prefer组成。

那不均使用它的完全排斥的传承。它是一个完全的均值传承回退位置。


If the relationship is"is-a" - use inheritance, and if the relationship is"has-a" - use composition.
Is it always right?

在某种意义上,是的。但你必须小心,不要引入不必要的、人为的"IS-A"关系。

例如,人们可能认为thickOrderedRectangle是一个矩形,乍一看似乎是合理的,并决定使用继承。但是这种情况可以更好地描述为一个矩形有一个边界,这个边界可以是也可以不是一个厚的顺序。在这种情况下,他更喜欢构图。

以同样的方式,人们可能会认为一个thickboard是一个特殊的边界并使用继承;但最好说一个边界有一个宽度,因此更喜欢组合。

在所有这些模棱两可的案例中,我的经验法则是三思而后行,正如其他人所建议的,更喜欢组合而不是继承。


我认为它的简单的"冰AA AA-"VS"有一个"AA克里特斯说,"我可以得到很blurry线。它不喜欢的两人总是会来的两个相同的结论,只是作为一个给定的指南。

也为克里特斯说,prefer组合物在传承。我心中有两个,有两个很好的原因derive两类从一个基地和茶叶基地'真的需要两个类应该已经被设计为与传承,德科工的一种专业你想申请。

和超越,这可能会是个理想的信息是unpopular下两个家伙的味道和感觉。小时我想得到一个更好的开发人员的好感,当威尔大学传承的工作和当它不会好,但他们可能很难找到它的明确表示。我知道我找到它的硬,这demonstrates作为答案。也许我只是projecting的困难:虽然其他人onto)


传承不均,总是有一个"冰"的关系和缺乏一个不总是有不均。

例子:

  • 如果你使用保护或私人 你失去外部传承 这是substitutability,AA,AA的父亲 任何人在你的冰淇淋系列 有关衍生冰槽(A型) 基地。
  • 如果你重写一座虚拟人行为改变observable虔诚的人referencing的基地,从原始的基础实施,那么你必须substitutability有效破碎。即使你有一个公共层次传承衍生冰槽的基地。
  • 你的课,有时是可以substituitable传承为另一个"没有任何关系的工作。例如,如果你是使用模板和identical接口成员函数的适当的教育"的教育是个椭圆&;"在椭圆和圆形perfectly。我可以是一个圆substituitable教育&;"。

是我想说这里的冰,它需要很多的思想和工作保持一个"冰"的两个类之间的关系substitutable传承不管你使用或不。


我认为约翰有正确的想法。你把你的课堂关系看作是建立模型,当他们开始教你OOP原则时,他们会试图让你去做。实际上,你最好看看代码体系结构中的事物是如何工作的。也就是说,对于其他程序员(或您自己)来说,在不破坏代码的情况下重新使用代码,或者查看实现以了解它的功能,最好的方法是什么?

我发现继承常常打破了"黑匣子"的理想,所以如果信息隐藏很重要,那么它可能不是最好的方法。我越来越多地发现,与在其他地方重用组件相比,继承对于提供公共接口更好。

当然,每一种情况都是独一无二的,没有正确的方法来做出这个决定,只有经验法则。


人们往往说,传承是一个"冰"的关系,所以你可以为你的麻烦。传承在C + +为双分裂的思想:代码重用和defining接口。

第一次说"我的冰淇淋,这样其他类的类。只是在写代码的重用,他们之间的三角洲和其他执行从其他AA级AA不多。"

在第二个取决于对抽象类和基地是一个列表的两类方法实施的承诺。

第一次可以很方便,但它也可以维护的问题,因为如果做得不好所以有些人会走母猪AA的爸爸说你要永远不会做的。大多数人在第二emphasize传承,用其他的语言对我没有电话的接口。


部分> <无> < /是的一部分。如果冰"的关系,有一个"使用的成分。(补充说:"原始版本"使用的传承问题说:"我一个简单的typo校正,但第一次圣餐的话我的答案从"无"两个"是的"。)

组合物和使用城市的默认使用的传承;只有当必要的(但后来多尼hesitate使用它)。


我的拇指规则(虽然冰槽混凝土),如果我可以使用相同的代码在不同的类,然后把这类代码到父母和使用的传承。否则使用的成分。

这两个原因我写更少的代码更容易吗?这是inherently保持。