【问题标题】:why does vb.net not support multiple inheritance?为什么 vb.net 不支持多重继承?
【发布时间】:2010-05-03 22:51:19
【问题描述】:

我看到了一些关于为什么 c# 不实现多重继承的讨论,但很少讨论为什么它在 vb 中不受支持。我知道 c# 和 vb 都被编译为中间语言,因此它们都需要共享类似的限制。

VB 中缺少多重继承似乎是 dot net 中缺少该功能的原因之一。有谁知道为什么VB不支持多重继承?我希望有一点历史课和讨论,为什么从来没有考虑过 VB。

【问题讨论】:

  • 您可能听说过有关 C# 的讨论,因为 C# 更接近支持 MI 的 C++。另一方面,VB 作为一种编程语言的主要目标是简单而不是复杂,因此大多数程序员并不期望 VB 支持 MI。

标签: .net vb.net history multiple-inheritance


【解决方案1】:

它没有在 CLR 中实现,因此在 VB.NET 等符合 CLS 的语言中不可用。包括 C# 首席架构师 Anders Hejlsberg 在内的 Microsoft 工程师似乎达成了普遍共识,即潜在的好处不值得付出成本和实现的复杂性。当时 .NET 团队的杰出工程师 Chris Brumme 早在 2004 年就说过:

我们没有提供内置的、可验证的、符合 CLS 的多重实现继承版本有几个原因:

  1. 不同的语言实际上对 MI 的工作方式有不同的期望。例如,如何解决冲突以及重复碱基是合并还是冗余。在我们可以在 CLR 中实现 MI 之前,我们必须对所有语言进行调查,找出共同的概念,并决定如何以与语言无关的方式来表达它们。我们还必须决定 MI 是否属于 CLS,以及这对于不想要这个概念的语言(例如 VB.NET)意味着什么。当然,这就是我们作为公共语言运行时所从事的业务,但我们还没有为 MI 做这件事。

  2. 真正适合 MI 的地方实际上很少。在许多情况下,多接口继承可以代替完成工作。在其他情况下,您可以使用封装和委托。如果我们要添加一个稍微不同的构造,比如 mixins,那实际上会更强大吗?

  3. 多重实现继承给实现注入了很多复杂性。这种复杂性会影响转换、布局、调度、字段访问、序列化、身份比较、可验证性、反射、泛型,可能还有很多其他地方。

目前还不清楚此功能是否会收回成本。这是我们经常被问到的问题。这是我们尚未尽职调查的事情。但我的直觉告诉我,在我们进行深入检查之后,我们仍然会决定不实现该功能。

[Link]

底线是我不会屏住呼吸。

现在,您可以通过继承多个接口并将实现委托给包含的类实例,从而获得多实现继承的一些好处(如果不是大部分的话)。还需要做一些工作,但这是我们目前最好的。

我还应该注意,我已经全职编写 C++ 好几年了,在我自己的设计中只使用了几次多重继承。当我需要它时它很方便,但老实说,我发现自己并不经常希望在 C# 中使用它。

【讨论】:

    【解决方案2】:

    所有 dotNET 语言共享一个通用类型系统,并且 CTS 不支持多重继承。像 VB 或 C# 这样的特定语言不能单独添加它,它将与 dotNET 的其余部分不兼容。最多一种语言可能会选择忽略/隐藏这样的功能。

    我不知道为什么不包括在内,但值得注意的是大多数语言不支持它。我只知道 C++,虽然基本应用程序很简单,有时也很有用,但它也带来了大量特殊的语法和规则。不是每个人都认为它物有所值。

    【讨论】:

    • 通常在 C++ 下,它的多重继承最好只用于支持一个基类 + 多个接口的模式,并且只有在你真的 - 真的 - 真的需要两个类中的一个时才会分支基类
    【解决方案3】:

    MI(多重继承)的缺乏与语言设计和预期宿主 (CLR) 密切相关:

    1) MI/SI 的差异对于一门语言而言如此重要,以至于以后很难(或者可能不可能)将其“添加为功能”。

    2) 至于预期的宿主:虽然 可以为 CLR 编写 MI 语言(就像可以为 CLR 编写带有延续等的语言一样) -- 可以做到)是,这样做,您将失去与所有其他“.NET”语言的互操作性

    可以改装到 CLR 中的更简单的“MI”形式是通过编译时 MRO 折叠处理的特征(这就是 Scala 在 JVM 上支持特征的方式)。然而,这仍然需要主要重新设计/重新思考语言,对于像 VB(.NET) 这样“经过审查”的东西,祝你好运:-) 必须确保它与现有代码配合得很好对语言进行改进是一件大事。

    【讨论】:

      【解决方案4】:

      还有许多其他技术被证明远远优于 MI,例如组合。即使在像 C++ 这样支持 MI 的语言中,实际上也很少看到一个类从两个非抽象基类乘以继承。

      【讨论】:

        【解决方案5】:

        为什么 C# 或 VB.NET 不支持多重继承

        http://royalarun.blogspot.in/2013/05/why-c-or-vbnet-doesnt-support-multiple.html

        1) 第一个原因是 Diamond 问题的歧义,考虑一个类 A 有 foo() 方法,然后 B 和 C 从 A 派生并且有自己的 foo() 实现,现在类 D 使用多重继承从 B 和 C 派生如果我们只引用 foo() 编译器将无法决定它应该调用哪个 foo() 。这也称为钻石问题,因为这种继承场景的结构类似于 4 边钻石,见下文

              A foo()
               / \
              /   \  
        foo() B     C foo()  
              \   /  
               \ /  
                D
               foo()
        

        在我看来,即使我们移除菱形类 A 的顶头并允许多重继承,我们也会看到这个歧义问题。

        有时候,如果你把这个理由告诉面试官,他会问 C++ 是否可以支持多重继承,而不是为什么不支持 c# 或 vb.net。在这种情况下,我会尝试向他解释我在下面给出的第二个原因,这不是因为技术难度,但更易于维护和更清晰的设计是驱动因素,尽管这只能由任何 Java 设计师证实,我们只能推测。 Wikipedia 链接很好地解释了在使用多重继承时如何因菱形问题而出现不同的语言地址问题。

        2) 对我来说,第二个也是更令人信服的理由是多重继承确实使设计复杂化,并在强制转换、构造函数链接等过程中产生问题,并且鉴于您需要多重继承的场景并不多,因此明智的决定是省略它为了简单。 C# 也通过支持接口的单一继承来避免这种歧义。由于接口只有方法声明并且不提供任何实现,因此特定方法只有一个实现,因此不会有任何歧义。

        【讨论】:

          【解决方案6】:

          假设B 类型有一个虚拟方法m,其中XY 类型的实现方式不同,尽管这两个实现都链接到base.m()D 派生自XY 而没有定义它自己的实现,GeorgeD 的一个实例。类X 将期望没有派生类将访问B.m() 而不通过其自己的该方法的实现,并且类Y 将具有类似的期望。编译器不能让CType(George,B).m() 做任何不违反这种期望的事情。如果从D 类型向上转换到B 需要经过XY 类型,那么经过X 的转换可以使用X 的方法和经过@987654341 的转换@ 可以使用Y 的方法,但是对D 的引用将不能被期望引用B(或者,就此而言,Object)的代码直接使用。要求只有接口可以被多重继承,并且实现接口的每个类型都必须提供所有方法的实现,这几乎与提供通用的多重继承一样好,但不会导致同样的歧义。

          【讨论】:

            猜你喜欢
            • 2011-04-15
            • 2011-02-21
            • 2016-04-18
            • 2014-03-04
            • 2011-03-17
            • 2011-03-24
            • 2011-05-06
            • 2011-02-20
            相关资源
            最近更新 更多