...或者它们是同一件事吗?我注意到每个都有自己的 Wikipedia 条目:Polymorphism、Multiple Dispatch,但我无法看到这些概念的不同之处。
编辑:重载如何适应这一切?
...或者它们是同一件事吗?我注意到每个都有自己的 Wikipedia 条目:Polymorphism、Multiple Dispatch,但我无法看到这些概念的不同之处。
编辑:重载如何适应这一切?
多态性是允许语言/程序在运行时根据发送到该方法的参数类型决定调用哪个方法的工具。
语言/运行时使用的参数数量决定了语言支持的多态性的“类型”。
单一调度是一种多态性,其中仅使用一个参数(消息的接收者 -this
或self
)来确定调用。
多重分派是一种多态性,其中使用多个参数来确定调用哪个方法。在这种情况下,接收者以及方法参数的类型用于告诉调用哪个方法。
所以你可以说多态是一个通用术语,而多次和单次调度是特定类型的多态。
附录:重载发生在编译期间。它使用编译期间可用的类型信息来确定要调用的方法类型。单/多分派发生在运行时。
示例代码:
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 { }
}
}
使用多重分派,一个方法可以有多个参数传递给它,并且使用哪个实现取决于每个参数的类型。评估类型的顺序取决于语言。在 LISP 中,它从头到尾检查每种类型。具有多重分派的语言使用泛型函数,它们只是函数声明,不像泛型方法,后者使用类型参数。
多重分派允许子类型化方法调用的参数多态性。
单一分派还允许一种更有限的多态性(对实现相同接口或继承相同基类的对象使用相同的方法名称)。这是多态性的经典示例,其中您的方法在子类中被覆盖。
除此之外,泛型还提供参数类型多态性(即,相同的泛型接口可用于不同类型,即使它们不相关——例如List<T>
:它可以是任何类型的列表,并且无论如何都以相同的方式使用)。
Multiple Dispatch 更类似于函数重载(如在 Java/C++ 中所见),不同之处在于调用的函数取决于参数的运行时类型,而不是它们的静态类型。
我以前从未听说过 Multiple Dispatch,但是在浏览了 Wikipedia 页面之后,当与方法的参数一起使用时,它看起来很像 MD 是一种多态性。
多态性本质上是一个对象可以被看作是它的基础的任何类型的概念。因此,如果您有 aCar
和 a Truck
,它们都可以被视为 a Vehicle
。这意味着您可以Vehicle
为任何一个调用任何方法。
多重分派看起来很相似,因为它允许您使用多种类型的参数调用方法,但是我在描述中没有看到某些要求。首先,它似乎不需要一个通用的基本类型(我无法想象没有 THAT 的实现void*
),并且您可以涉及多个对象。
因此Start()
,您可以调用在StartObject(Object C)
其他地方定义的方法并对其进行编码以在运行时检查参数类型并适当地处理它,而不是在列表中的每个对象上调用该方法(这是一个经典的多态示例)。这里的区别在于Start()
方法必须内置在类中,而StartObject()
方法可以在类之外定义,因此各种对象不需要符合接口。
Start()
如果需要使用不同的参数调用该方法,这可能会很好。也许Car.Start(Key carKey)
对。Missile.Start(int launchCode)
但两者都可以称为StartObject(theCar)
或StartObject(theMissile)
有趣的概念...
如果您想要方法调用的概念等价物
(obj_1, obj_2, ..., obj_n)->method
要依赖于元组中的每个特定类型,那么您需要多次调度。多态对应于 n=1 的情况,是 OOP 的必要特征。
Multiple Dispatch 是一种多态性。在 Java/C#/C++ 中,通过继承和覆盖存在多态性,但这不是基于两个或多个参数的多分派(不仅仅是this
,就像在 Java/C#/C++ 中那样)
Multiple Dispatch 依赖于基于多态性。在 C++、C#、VB.NET 等中遇到的典型多态性使用单一调度——即被调用的函数仅依赖于单个类实例。多次调度依赖于多个类实例。