【问题标题】:When might multiple inheritance be the only reasonable solution? [closed]多重继承何时可能是唯一合理的解决方案? [关闭]
【发布时间】:2009-07-07 18:37:37
【问题描述】:

要清楚,我不是在问多重继承是好是坏。我从那场辩论的双方那里听到了很多争论。

我想知道在 C++ 中是否存在任何类型的设计问题或场景,其中多重继承要么是完成某事的唯一方式,要么至少是所有其他替代方案的最佳方式,以至于它不会考虑其他任何事情都没有意义。

显然,这个问题不适用于不支持多重继承的语言。

【问题讨论】:

标签: c++ multiple-inheritance


【解决方案1】:

policy-based design 不能没有多重继承。因此,如果基于策略的设计是解决您的问题的最优雅的方式,那么这意味着您需要多重继承来解决您的问题,而不是所有其他选项。

如果不滥用多重继承(就像一切,任何语言),多重继承会非常有用。

【讨论】:

  • 这是否意味着基于策略的设计根本不可能在诸如 Java 之类的语言中实现,或者有办法解决它吗?
  • 实际上,链接文章表明多重继承只是最常见的实现模式(具有一些显着优势),而不是绝对需要。
  • @Jeff L:Java 中的“代理”类可以用作解决方法。
  • 不是基于策略的设计通常工作的方式,不,我认为 Java 做不到。它可能能够做替代方案,其中每个策略都有成员变量而不是从它继承,但这失去了继承的一些优势。 Java是否可以使用这样的模板,我不知道。
  • @GMan:使用 Java 中的一些样板,您可以将编码时已知的方法(因此特别是主机实际调用的任何方法)委托给策略对象,并为它们提供访问器。在 C++ 版本中,主机会自动扩展其接口以包含用户所需的任意函数,并嵌入到他们的 mixin 类中。因此,我想这取决于您(或者正确地说,Alexandrescu)是否认为此功能与“政策模式”本身或它的固有部分是可分离的。在 Java 中,您仍然可以允许用户恢复策略对象、向下转换和调用。
【解决方案2】:

在这种情况下,您会从一个类继承,并可能在 Java 中实现一个或两个接口。我认为这是您可以通过 C++ 中的多重继承来解决的问题。

【讨论】:

    【解决方案3】:

    C++ 流使用多重继承:istreamostream 都是 iostream 的父级。因为它们都继承自ios_base,所以你有一颗钻石。

    这是唯一“合理”的解决方案,因为标准库的流部分采用与算法和集合相同的路线是不合理的。所以 ostream 的行为是多态的,而不是像 Iterator(*) 这样的“鸭子类型”接口。

    一旦有了动态多态性,就需要多重继承来同时实现多个接口。

    (*) 大概这是因为其他任何事情都会一团糟。您必须能够编写操作流的实际函数,而不是强迫用户到处都有模板。这是因为写“一些流,直到运行时我才知道什么”是很常见的,但不想操作“一些集合,直到运行时我才知道什么”。

    【讨论】:

      【解决方案4】:

      如果您需要继承行为,而不仅仅是契约,多重继承很有用。然而,正如其他语言所展示的那样,多重继承并不是解决该问题的唯一方法,其代价是使继承树更深。因此,您必须只能使用多重继承的情况非常少见。

      【讨论】:

        【解决方案5】:

        我已经阅读了 Java 接口等内容,以便更好地了解这个问题的答案。接口背后的想法是创建一个抽象类,作为另一个类的模板。这里的优点是模板可以在一个具体的类中组合。例如-

        父类- FoodStore 子类-CoffeeShop 子类-面包店

        使用此继承树,FoodStore 可以是 Bakery 或 CoffeeShop,但不能同时是两者。但那我们怎么称呼星巴克呢?

        更好的方法,IMO-

        父类- FoodStore 界面-CoffeeShop 界面-面包店

        公共类 Starbucks 扩展 FoodStore 实现 CoffeeShop、Bakery { ... }

        您必须了解一点 Java 才能理解这一点,但必须掌握它。接口相当初级,IMO。

        作为进一步的思考,也许接口的设计是为了遵守“不要重复自己”。很明显,既然我提到了它。

        【讨论】:

          【解决方案6】:

          当您想要继承功能而不是角色时,例如 boost::noncopyable(支持此功能的其他语言(与 Java 和 C# 不同)将其称为 mixin)。

          【讨论】:

            【解决方案7】:

            正如其他答案所说:

            还有:

            【讨论】:

              【解决方案8】:

              当您必须组合两个或多个第三方类层次结构时,每个层次结构都要求对象从层次结构自己的基类派生,那么缺少多重继承将使您的代码复杂而繁琐。

              namespace Object_Database {
                  class Object {
                    public:
                      virtual void store() ;
                      virtual void fetch() ;
                  };
              }
              
              namespace Reflectives {
                  class Object {
                    public:
                      virtual std::vector<std::string> > membernames();
                      virtual std::vector<std::string> > methodnames();
                  };
              }
              

              第一个层次结构允许用户创建可以序列化到对象数据库和从对象数据库中序列化的对象,并要求所有此类对象都派生自 Object_Database::Object 类。第二个层次结构允许用户创建可以在运行时查询其成员名称的对象,并要求所有此类对象都派生自 Reflectives::Object。

              如果你需要可以同时做这两件事的对象,你只需要写:

                class ReflectivePickle : 
                public Object_Database::Object, 
                public Reflectives::Object {
                  // ...
                };
              

              其他解决方案不合理。

              【讨论】:

                【解决方案9】:

                当基类是“接口类”时,我倾向于在 C++ 中使用多重继承,即所有方法都是纯虚拟的基类,没有一个实现 [记住你仍然可以定义一个实现,但你必须显式调用它],并且没有数据成员。非常类似于 Java 或(据我所知)C# 中的“接口”。

                要在 C++ 中使用多态,不能使用组合,必须使用(公共)继承。

                因此,如果 Bar 类(公开)继承自 Printable 和 Serializable,我可以将对象视为可打印对象、可序列化对象或 Bar 对象(使用指针或引用)。

                对于作曲,你无法做到这一点。

                【讨论】:

                  【解决方案10】:

                  如果您想查看多继承的漂亮实现,请查看 Eiffel。他们通过特征重命名解决了菱形问题,比范围解析简单得多,它甚至支持直接重复继承,例如:

                  A继承B、B、B

                  当需要使用这种类型的继承时。

                  他们的内核库是开源的,如果您想查看示例,则广泛使用多重继承。

                  http://sourceforge.net/projects/eiffelstudio/files/

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2012-08-14
                    • 1970-01-01
                    • 2012-11-15
                    • 2019-04-09
                    • 2023-04-08
                    相关资源
                    最近更新 更多