多态性和多分派有啥区别?

Posted

技术标签:

【中文标题】多态性和多分派有啥区别?【英文标题】:What's the difference between Polymorphism and Multiple Dispatch?多态性和多分派有什么区别? 【发布时间】:2010-09-12 14:36:03 【问题描述】:

...或者它们是同一个东西?我注意到每个都有自己的 Wikipedia 条目:Polymorphism、Multiple Dispatch,但我很难看出这些概念有何不同。

编辑:Overloading 是如何适应这一切的?

【问题讨论】:

【参考方案1】:

多态是允许语言/程序在运行时根据发送给该方法的参数类型决定调用哪个方法的工具。

语言/运行时使用的参数数量决定了一种语言支持的多态的“类型”。

单分派是一种多态性,其中仅使用一个参数(消息的接收者 - thisself)来确定调用。

多重分派是一种多态性,其中使用多个参数来确定调用哪个方法。在这种情况下,接收者以及方法参数的类型用于告诉调用哪个方法。

所以你可以说多态是一个通用术语,而多次和单次调度是特定类型的多态。

附录:重载发生在编译期间。它使用编译期间可用的类型信息来确定要调用的方法类型。单/多分派发生在运行时。

示例代码:

using NUnit.Framework;

namespace SanityCheck.UnitTests.***

    [TestFixture]
    public class DispatchTypes
    
        [Test]
        public void Polymorphism()
        
            Baz baz = new Baz();
            Foo foo = new Foo();

            // overloading - parameter type is known during compile time
            Assert.AreEqual("zap object", baz.Zap("hello"));
            Assert.AreEqual("zap foo", baz.Zap(foo));


            // virtual call - single dispatch. Baz is used.
            Zapper zapper = baz;
            Assert.AreEqual("zap object", zapper.Zap("hello"));
            Assert.AreEqual("zap foo", zapper.Zap(foo));


            // C# has doesn't support multiple dispatch so it doesn't
            // know that oFoo is actually of type Foo.
            //
            // In languages with multiple dispatch, the type of oFoo will 
            // also be used in runtime so Baz.Zap(Foo) will be called
            // instead of Baz.Zap(object)
            object oFoo = foo;
            Assert.AreEqual("zap object", zapper.Zap(oFoo));
        

        public class Zapper
        
            public virtual string Zap(object o)  return "generic zapper" ; 
            public virtual string Zap(Foo f)  return "generic zapper"; 
        

        public class Baz : Zapper
        
            public override string Zap(object o)  return "zap object"; 
            public override string Zap(Foo f)  return "zap foo"; 
        

        public class Foo  
    

【讨论】:

出色的答案! A++++++ 会再次询问 谢谢!这帮助我整理了我在***上阅读的概念。【参考方案2】:

使用多重分派,一个方法可以有多个参数传递给它,使用哪个实现取决于每个参数的类型。评估类型的顺序取决于语言。在 LISP 中,它从头到尾检查每种类型。 具有多重分派的语言使用泛型函数,它们只是函数声明,不像泛型方法,后者使用类型参数。

多重分派允许subtyping polymorphism 方法调用的参数。

单次分派还允许一种更有限的多态性(对实现相同接口或继承相同基类的对象使用相同的方法名称)。这是多态性的经典示例,其中您的方法在子类中被覆盖。

除此之外,generics 提供参数类型多态性(即,相同的泛型接口可用于不同类型,即使它们不相关 - 例如List<T>:它可以是一个列表任何类型,并且无论如何都以相同的方式使用)。

【讨论】:

【参考方案3】:

Multiple Dispatch 更类似于函数重载(如在 Java/C++ 中所见),不同之处在于调用的函数取决于参数的运行时类型,而不是它们的静态类型。

【讨论】:

【参考方案4】:

我以前从未听说过 Multiple Dispatch,但是在浏览 Wikipedia 页面后,当与方法的参数一起使用时,它看起来很像 MD 是一种多态性。

多态本质上是一个对象可以被视为任何类型的概念,它是它的基础。因此,如果您有CarTruck,它们都可以被视为Vehicle。这意味着您可以为任何一个调用任何Vehicle 方法。

Multiple dispatch 看起来很相似,因为它允许您使用多种类型的参数调用方法,但是我在描述中没有看到某些要求。首先,它似乎不需要一个通用的基本类型(我无法想象在没有void* 的情况下实现 THAT),并且您可以涉及多个对象。

因此,您可以调用在其他地方定义的StartObject(Object C) 方法并对其进行编码以在运行时检查参数类型并处理它适当地。这里的区别是Start()方法必须内置在类中,而StartObject()方法可以定义在类之外,因此各种对象不需要符合接口。

如果需要使用不同的参数调用 Start() 方法,这可能会很好。也许Car.Start(Key carKey)Missile.Start(int launchCode)

但两者都可以称为StartObject(theCar)StartObject(theMissile)

有趣的概念...

【讨论】:

【参考方案5】:

如果你想要方法调用的概念等价物

(obj_1, obj_2, ..., obj_n)->method

要依赖于元组中的每个特定类型,那么您需要多次分派。多态对应于n=1的情况,是OOP的必要特征。

【讨论】:

【参考方案6】:

Multiple Dispatch 依赖于基于多态性。在 C++、C#、VB.NET 等中遇到的典型多态性使用单一调度——即被调用的函数仅依赖于单个类实例。多次调度依赖于多个类实例。

【讨论】:

【参考方案7】:

Multiple Dispatch 是一种多态性。在 Java/C#/C++ 中,通过继承和覆盖存在多态性,但这不是基于两个或多个参数的多分派(不仅仅是this,就像在 Java/C#/C++ 中一样)

【讨论】:

以上是关于多态性和多分派有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

Java中的重载和多分派

生物学上的多样性diversity与多态性polymorphisms有啥区别

多态性实现机制——静态分派与动态分派

动态方法分派和运行时多态性错误

深入Java虚拟机之五:多态性实现机制——静态分派与动态分派

重载和重写有啥区别