多态和多重分派有什么区别?

35

多态和多重分派是否相同?我注意到它们各自都有自己的维基百科条目: PolymorphismMultiple Dispatch,但我很难看出这些概念有何不同。

编辑: 那么重载又如何适用于所有这些内容呢?

7个回答

55

多态是一种机制,它允许语言/程序在运行时根据发送给该方法的参数的类型来做出决策,以确定调用哪个方法。

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

单分派是一种多态类型,只使用一个参数(消息接收者 - thisself)来确定调用。

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

因此,你可以说多态是一个通用术语,而多分派和单分派则是特定的多态类型。

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

示例代码:

using NUnit.Framework;

namespace SanityCheck.UnitTests.StackOverflow
{
    [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 { }
    }
}

9
非常棒的回答!A++++++ 会再次提问。 - raldi
1
谢谢!这个帮助我整合了我在维基百科上阅读的概念。 - John

3

使用多重分派,方法可以接受多个参数,并且使用哪个实现取决于每个参数的类型。这些类型的评估顺序取决于语言。在LISP中,它从第一个类型开始逐个检查。

具有多重分派功能的语言使用通用函数,它们只是函数声明,不像使用类型参数的通用方法。

多重分派允许在方法调用时对参数进行子类型多态处理 (译者注:subtyping polymorphism 的翻译)

单重分派也允许一种更有限的类型多态性(为实现相同接口或继承相同基类的对象使用相同的方法名称)。这是多态性的经典示例,其中你需要在子类中重写方法。

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


2

多重分发更类似于函数重载(如Java/C ++中所见),但调用的函数取决于参数的运行时类型,而不是它们的静态类型。


2
我以前从未听说过多重分派,但是在浏览维基百科页面后,它看起来很像多态的一种类型,当与方法的参数一起使用时。多态本质上是一个对象可以被视为其基类的任何类型。所以如果你有一个Car和一个Truck,它们都可以被视为Vehicle。这意味着你可以为任何一个调用Vehicle方法。
多重分派看起来很相似,因为它允许您使用多种类型的参数调用方法,但是我在描述中没有看到某些要求。首先,它似乎不需要共同的基类型(我无法想象实现这个功能而不使用void*),并且您可以涉及多个对象。
因此,您可以调用其他地方定义的StartObject(Object C)方法,对运行时检查的参数类型进行编码,并适当处理它。这里的区别是Start()方法必须内置到类中,而StartObject()方法可以在类外定义,因此各种对象不需要符合接口。
如果需要使用不同的参数调用Start()方法,这可能很有用。也许是Car.Start(Key carKey) vs. Missile.Start(int launchCode)。但是两者都可以被称为StartObject(theCar)StartObject(theMissile)
有趣的概念...

1

如果您想要方法调用的概念等效项

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

如果要依赖于元组中的每个特定类型,则需要多重分派。 多态对应于n = 1的情况,并且是面向对象编程的必要特性。


0

多重分派是一种多态性。在Java/C#/C++中,通过继承和覆盖实现了多态性,但这不是多重分派,它基于两个或更多参数(不仅仅是像Java/C#/C++中的this)。


0

多重分派依赖于基于多态性。在C++、C#、VB.NET等语言中遇到的典型多态性使用单一分派——即被调用的函数仅取决于单个类实例。而多重分派则依赖于多个类实例。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接