gpt4 book ai didi

c++ - 为什么我应该避免 C++ 中的多重继承?

转载 作者:行者123 更新时间:2023-12-01 16:41:31 25 4
gpt4 key购买 nike

使用多重继承是一个好概念还是我可以做其他事情?

最佳答案

多重继承(缩写为 MI)的味道,这意味着通常是出于糟糕的原因而做的,它会在维护者面前反击。
总结

  • 考虑特征组合,而不是继承
  • 小心恐惧之钻
  • 考虑继承多个接口(interface)而不是对象
  • 有时,多重继承是正确的。如果是,那么使用它。
  • 准备好在代码审查中捍卫您的多继承架构

  • 1. 也许是组合?
    这对于继承来说是正确的,因此对于多重继承更是如此。
    你的对象真的需要从另一个继承吗?一个 Car不需要从 Engine 继承上类,也不从 Wheel .一个 Car有一个 Engine和四个 Wheel .
    如果您使用多重继承而不是组合来解决这些问题,那么您就做错了。
    2. 恐惧钻石
    通常,您有一个类(class) A ,然后 BC两者都继承自 A .并且(不要问我为什么)然后有人决定 D必须从 B 继承两者和 C .
    我在八八年里遇到过两次这样的问题,很有趣,因为:
  • 从一开始就犯了多大的错误(在这两种情况下, D 不应该从 BC 继承),因为这是糟糕的架构(实际上, C 不应该存在于所有...)
  • 维护人员为此付出了多少,因为在 C++ 中,父类 A曾两次出现在其孙子类D ,从而更新一个父字段 A::field意味着要么更新它两次(通过 B::fieldC::field ),或者有一些事情悄悄出错并崩溃,稍后(在 B::field 中新建一个指针,并删除 C::field ...)

  • 如果这不是您想要的,则在 C++ 中使用关键字 virtual 来限定继承可避免上述双重布局,但无论如何,根据我的经验,您可能做错了什么......
    在对象层次结构中,您应该尝试将层次结构保持为树(一个节点有一个父节点),而不是图形。
    关于钻石的更多信息(编辑 2017-05-03)
    C++ 中恐惧钻石的真正问题(假设设计是合理的 - 审查您的代码!),是您需要做出选择:
  • 类(class)是否可取A在您的布局中存在两次,这意味着什么?如果是,那么一定要从它继承两次。
  • 如果它应该只存在一次,那么虚拟地继承它。

  • 这种选择是问题所固有的,在 C++ 中,与其他语言不同,您实际上可以做到这一点,而无需教条在语言级别强制您的设计。
    但与所有权力一样,这种权力也伴随着责任:审查您的设计。
    3. 接口(interface)
    零个或一个具体类和零个或多个接口(interface)的多重继承通常是可以的,因为您不会遇到上述的恐惧钻石。事实上,这就是 Java 中的工作方式。
    通常,当 C 继承自 A 时,您的意思是什么和 B是用户可以使用 C好像它是一个 A ,和/或好像它是 B .
    在 C++ 中,接口(interface)是一个抽象类,它具有:
  • 它的所有方法都声明为纯虚拟(后缀 = 0)(删除了 2017-05-03)
  • 无成员变量

  • 零到一个真实对象和零个或多个接口(interface)的多重继承不被认为是“臭的”(至少,没有那么多)。
    有关 C++ 抽象接口(interface)的更多信息(编辑 2017-05-03)
    首先,NVI 模式可用于生成接口(interface),因为真正的标准是没有状态(即没有成员变量,除了 this )。你的抽象接口(interface)的重点是发布一个契约(Contract)(“你可以这样称呼我,这样称呼我”),仅此而已。只有抽象虚拟方法的限制应该是一种设计选择,而不是一种义务。
    其次,在 C++ 中,从抽象接口(interface)虚拟继承是有意义的(即使有额外的成本/间接)。如果您不这样做,并且接口(interface)继承在您的层次结构中多次出现,那么您就会有歧义。
    第三,面向对象很棒,但它不是 C++ 中的唯一真相。使用正确的工具,并始终记住您在 C++ 中有其他范例提供不同类型的解决方案。
    4. 你真的需要多重继承吗?
    有时,是的。
    通常,您的 C类继承自 AB , 和 AB是两个不相关的对象(即不在同一个层次结构中,没有共同点,不同的概念等)。
    例如,您可以拥有一个 Nodes 的系统。具有 X,Y,Z 坐标,能够进行大量几何计算(可能是一个点,几何对象的一部分)并且每个节点都是一个自动代理,能够与其他代理进行通信。
    也许您已经可以访问两个库,每个库都有自己的 namespace (使用 namespace 的另一个原因……但是您使用 namespace ,不是吗?),其中一个是 geo另一个是 ai所以你有自己的 own::Node两者均来自 ai::Agentgeo::Point .
    这是您应该问自己是否不应该使用组合的时刻。如 own::Node真的是两个 ai::Agent和一个 geo::Point ,那么合成就不行了。
    然后你需要多重继承,有你的 own::Node根据他们在 3D 空间中的位置与其他代理进行通信。
    (您会注意到 ai::Agentgeo::Point 完全、完全、完全无关……这大大降低了多重继承的危险)
    其他案例(编辑 2017-05-03)
    还有其他情况:
  • 使用(希望是私有(private)的)继承作为实现细节
  • 一些 C++ 习语如策略可以使用多重继承(当每个部分需要通过 this 与其他部分通信时)
  • 来自 std::exception ( Is Virtual Inheritance necessary for Exceptions? )
  • 的虚拟继承

  • 有时你可以使用组合,有时 MI 更好。重点是:你有选择。负责任地做(并审查您的代码)。
    5. 那么,我应该做多重继承吗?
    大多数时候,根据我的经验,没有。 MI 不是正确的工具,即使它看起来有效,因为它可以被懒惰的人使用,而不会意识到后果(例如使 Car 同时成为 EngineWheel )。
    但有时,是的。那时,没有什么比 MI 更好用了。
    但是因为 MI 很臭,所以准备在代码审查中捍卫你的架构(捍卫它是一件好事,因为如果你无法捍卫它,那么你就不应该这样做)。

    关于c++ - 为什么我应该避免 C++ 中的多重继承?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/406081/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com