……それとも同じものですか?それぞれに独自のウィキペディア エントリがあることに気付きました: Polymorphism、Multiple Dispatchですが、概念がどのように異なるかを理解するのに苦労しています。
編集:そして、オーバーロードはこれらすべてにどのように適合しますか?
……それとも同じものですか?それぞれに独自のウィキペディア エントリがあることに気付きました: Polymorphism、Multiple Dispatchですが、概念がどのように異なるかを理解するのに苦労しています。
編集:そして、オーバーロードはこれらすべてにどのように適合しますか?
ポリモーフィズムとは、言語/プログラムが実行時に、そのメソッドに送信されるパラメーターのタイプに基づいて、どのメソッドを呼び出すかを決定できるようにする機能です。
言語/ランタイムで使用されるパラメーターの数によって、言語でサポートされるポリモーフィズムの「タイプ」が決まります。
単一ディスパッチは、呼び出しを決定するために1 つのパラメーター (メッセージの受信者 - 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>
: 任意の型のリストにすることができ、関係なく同じように使用されます)。
多重ディスパッチは、呼び出される関数が静的型ではなく実行時型の引数に依存することを除いて、関数のオーバーロード(Java / C ++で見られるように)に似ています。
Multiple Dispatch については聞いたことがありませんが、ウィキペディアのページをちらりと見てみると、MD がメソッドへの引数と一緒に使用されると、ポリモーフィズムの一種のように見えます。
ポリモーフィズムとは、基本的に、オブジェクトをそのベースである任意の型と見なすことができるという概念です。したがって、 と がある場合Car
、Truck
それらは両方とも と見なすことができますVehicle
。Vehicle
これは、どちらに対しても任意のメソッドを呼び出すことができることを意味します。
複数のディスパッチは、複数の型の引数でメソッドを呼び出すことができるという点で似ていますが、説明には特定の要件がありません。まず、共通の基本型を必要としないようで ( なしで THAT を実装することは想像できませんでしたvoid*
)、複数のオブジェクトを含めることができます。
Start()
したがって、リスト内のすべてのオブジェクトに対してメソッドを呼び出す (これは典型的なポリモーフィズムの例です) 代わりに、別のStartObject(Object C)
場所で定義されたメソッドを呼び出して、実行時に引数の型をチェックし、適切に処理するようにコーディングできます。ここでの違いは、Start()
メソッドをクラスに組み込む必要があるのに対し、StartObject()
メソッドはクラスの外部で定義できるため、さまざまなオブジェクトがインターフェイスに準拠する必要がないことです。
Start()
メソッドを異なる引数で呼び出す必要がある場合、これは便利です。多分Car.Start(Key carKey)
vs.Missile.Start(int launchCode)
ただし、どちらもまたはとして呼び出すことができStartObject(theCar)
ますStartObject(theMissile)
面白いコンセプト...
メソッド呼び出しと同等の概念が必要な場合
(obj_1, obj_2, ..., obj_n)->method
タプル内の特定のタイプごとに依存するには、複数のディスパッチが必要です。ポリモーフィズムは n=1 の場合に対応し、OOP に必要な機能です。
多重ディスパッチは一種のポリモーフィズムです。Java / C#/ C ++では、継承とオーバーライドによるポリモーフィズムがありますが、これは2つ以上の引数に基づく多重ディスパッチではありません(this
Java / C#/ C ++のようにだけではありません)。
多重ディスパッチは、ポリモーフィズムベースに依存しています。C ++、C#、VB.NETなどで発生する典型的なポリモーフィズムは単一のディスパッチを使用します。つまり、呼び出される関数は単一のクラスインスタンスにのみ依存します。複数のディスパッチは、複数のクラスインスタンスに依存しています。