複数のディスパッチとは何かを理解しようとしています。いろいろなテキストをたくさん読んだのですが、マルチディスパッチとは何か、何に役立つのか、いまだによくわかりません。たぶん、私が見逃しているのは、複数のディスパッチを使用するコードです。C++には単一のディスパッチしかないため、適切にコンパイル/実行できないことがわかるように、複数のディスパッチを使用してC++で小さなコードを記述できますか? 私は違いを見る必要があります。ありがとう。
3 に答える
マルチディスパッチは、関数呼び出しに渡される引数の実行時の型に基づいて、呼び出す関数のバージョンを選択する機能です。
C++ で正しく動作しない例を次に示します (未テスト):
class A { };
class B : public A { };
class C : public A { }
class Foo
{
virtual void MyFn(A* arg1, A* arg2) { printf("A,A\n"); }
virtual void MyFn(B* arg1, B* arg2) { printf("B,B\n"); }
virtual void MyFn(C* arg1, B* arg2) { printf("C,B\n"); }
virtual void MyFn(B* arg1, C* arg2) { printf("B,C\n"); }
virtual void MyFn(C* arg1, C* arg2) { printf("C,C\n"); }
};
void CallMyFn(A* arg1, A* arg2)
{
// ideally, with multi-dispatch, at this point the correct MyFn()
// would be called, based on the RUNTIME type of arg1 and arg2
pFoo->MyFn(arg1, arg2);
}
...
A* arg1 = new B();
A* arg2 = new C();
// Using multi-dispatch this would print "B,C"... but because C++ only
// uses single-dispatch it will print out "A,A"
CallMyFn(arg1, arg2);
複数のディスパッチは、実行される関数が複数のオブジェクトのランタイム タイプに依存する場合です。
仮想関数を使用する場合、実行される実際の関数は -> または . オペレーター。
複数のディスパッチの実際のプログラミングのケースを考えるのに苦労しています。いろいろなキャラクターが戦うゲームかもしれません。
void Fight(Opponent& opponent1, Opponent& opponent2);
戦いの勝者は、両方の対戦相手の特性に依存する可能性があるため、両方の引数の実行時の型に応じて、この呼び出しを次のいずれかにディスパッチすることができます。
void Fight(Elephant& elephant, Mouse& mouse)
{
mouse.Scare(elephant);
}
void Fight(Ninja& ninja, Mouse& mouse)
{
ninja.KarateChop(mouse);
}
void Fight(Cat& cat, Mouse& mouse)
{
cat.Catch(mouse);
}
void Fight(Ninja& ninja, Elephant& elephant)
{
elephant.Trample(ninja);
}
// Etc.
関数の動作は、一方だけでなく両方の引数の型によって異なります。C++ では、これをいくつかの仮想関数として記述しなければならない場合があります。仮想関数は、1 つの引数 (this ポインター) に応じて選択されます。次に、仮想関数には、他の引数に固有の何かを行うためのスイッチまたは何かを含める必要がある場合があります。
シングル ディスパッチでは、実行される関数はオブジェクト タイプのみに依存します。二重ディスパッチでは、実行される関数は オブジェクト タイプとパラメータに依存します。
次の例では、関数Area()
はシングル ディスパッチを使用して呼び出されIntersect()
、Shape パラメーターを受け取るため、ダブル ディスパッチに依存しています。
class Circle;
class Rectangle;
class Shape
{
virtual double Area() = 0; // Single dispatch
// ...
virtual double Intersect(const Shape& s) = 0; // double dispatch, take a Shape argument
virtual double Intersect(const Circle& s) = 0;
virtual double Intersect(const Rectangle& s) = 0;
};
struct Circle : public Shape
{
virtual double Area() { return /* pi*r*r */; }
virtual double Intersect(const Shape& s);
{ return s.Intersect(*this) ; }
virtual double Intersect(const Circle& s);
{ /*circle-circle*/ }
virtual double Intersect(const Rectangle& s);
{ /*circle-rectangle*/ }
};
例はこの記事に基づいています。