【问题标题】:C++ Multiple Inheritance to Implement PolymorphismC++ 多重继承实现多态性
【发布时间】:2015-03-17 15:42:21
【问题描述】:

JSF C++ Coding Standards 中,AV 规则 87 显示了抽象基类的图表和作为多重继承的实现。

  1. 此图试图显示什么?

  2. 在这个例子中,私有/保护继承的目的是什么?

  3. 如何将实现创建为基类?

  4. 来自 AV 规则 87 的图表显示 D1 继承自 impl;这是 impl 一个与接口无关的不同实现吗?

反病毒规则 87

层次结构应该基于抽象类。见 Stroustrup 2, 12.5.

理由: 基于抽象类的层次结构倾向于将设计重点放在生成干净的接口上,将实现细节排除在外 接口,并最小化编译依赖,同时允许 替代实现共存。参见附录 A 中的 AV 规则 87 例如。

...

附录 A - AV 规则 87

首选基于抽象类的层次结构。因此 图表顶部的层次结构优先于层次结构 在图表的底部。

使用形状的经典多态示例:

5。 我的实现会是以下吗?这对我来说似乎不正确。我担心,我错过了设计的目的。传统上,我希望 Right_Triangle 继承自 Triangle。

 class Shape{};                              // Interface
 class Right_Triangle{};                     // Impl    
 class Triangle : public Shape,
                  private Right_Triangle {}; // D1

【问题讨论】:

    标签: c++ inheritance multiple-inheritance


    【解决方案1】:

    您的示例大部分是正确的,并且符合 AV 87 的精神。但是您打错了,实现和公共类应该是相同的“种类”(因此,两者都应该是通用三角形,例如):

    class IShape { ... };      
    class TriangleImpl { ... }; 
    class Triangle : public IShape,
                     private TriangleImpl { ... };
    

    声称直角三角形是一个三角形的图表是错误的,并且是一种常见的误解。直角三角形不是三角形,除非您明确限制可以对三角形执行的操作(例如,将其设为只读)。三角形可以有任何你想要的边长。从三角形继承的类必须仍然像三角形一样*行为。它被称为Liskov Substitution Principle

    因为你不能在任何地方都使用RightTriangle 类,所以Triangle 类可以不受限制地使用,这使得Triangle 作为一个具体类毫无用处(你不能设置边长在三角形上) - 因此所示的继承层次结构只是糟糕的设计。

    类层次结构的设计不一定遵循维恩图,也不应该遵循“日常真理”。长期的软件工程实践表明,坚持使用 LSP 可以获得合理的继承图。

    是的,如果教科书没有提供满足 LSP 的具体设计,那么证明这种“直角三角形就是三角形”的疯狂是错误的。在形状的情况下,TrilateralQuadrilateral 接口必须是只读的,并且特定的顶点或边设置方法只能在派生类中提供,因为它们遵循不同的限制。派生的具体类需要一个扁平的层次结构(Square 不是Rectangle - 如果是,您可以为其设置两个不同的边长!)。同样,就 LSP 而言,Square 不是Quadrilateral,因为四边形可以有任意放置的顶点等。

    【讨论】:

    • 我不确定我是否理解 AV 87 的“精神”。我仍然不明白从您的实现继承的好处(或坏处)。你能详细说明一下吗?
    • @Jerunh 实现类被设计强制只做一件事情或工作的一个方面,这个方面必须是设计自包含的。 Triangle 类可能包含IShapeTriangleImpl 之间的一些普通适配器。它使交换实现变得更加容易。
    • @KubaOber:尽管我在回答中使用了“直角三角形是三角形”的说法,但我同意你的回答。也许这是 OO 的失败,因为代表现实的对象真的很困难。上下文(问题域)是这里的关键:如果对象代表图形,那么“直角三角形是三角形”的说法可能是正确的(尽管没用,直角三角形应该是一个实例),但对于几何实体,你是对的。顺便说一句:动物等级制度更糟糕。
    【解决方案2】:

    直角三角形是三角形,所以继承是相反的。

    在您的示例中,Shape 必须是根据编码规则的抽象类。所以shape只能声明纯虚函数如Print()、Load()、rotate()、...

    要从另一个实现继承(在形状层次结构旁边),不应使用公共继承。

    【讨论】:

    • 您能否进一步解释一下从另一个实现继承的意思?这样的例子是什么?
    • 这个例子的其他实现可能有点超现实,但是假设你想让你的三角形播放声音,那么它可以从声音制作类继承,那么它不应该使用公共继承,但提供它自己的函数来访问声音播放实现。
    猜你喜欢
    • 2015-10-26
    • 1970-01-01
    • 1970-01-01
    • 2021-03-29
    • 2015-07-30
    • 1970-01-01
    • 2016-08-09
    • 2020-07-01
    • 2013-12-25
    相关资源
    最近更新 更多