ダブルディスパッチ
上述の問題は、Visitor パターンで用いられているものと同様の手法で解決できる。SpaceShip と GiantSpaceShip がいずれも関数
を持っているとすると、先ほどの例ではうまく動作しなかったが、以下の例はうまく動作する。
この例は、期待通りに Asteroid hit a GiantSpaceShip および ExplodingAsteroid hit a GiantSpaceShipと表示する。 鍵はtheSpaceShipReference.CollideWith(theAsteroidReference); であり、 これはランタイムに下記のような動作をする。
theSpaceShipReference は参照であり、C++ は vtable から正しいメソッドを探し出し、GiantSpaceShip::CollideWith(Asteroid&)を呼び出す。
GiantSpaceShip::CollideWith(Asteroid&) 内では、inAsteroid は参照であるため、inAsteroid.CollideWith(*this) はもう一つの仮想関数テーブルの検索を行うことになる。この場合には、inAsteroid は ExplodingAsteroid への参照であり、ExplodingAsteroid::CollideWith(GiantSpaceShip&) が呼び出される。
前述のように二項演算子という、(LispやForthなどを除いた)多くのプログラミング言語で好まれている機能において望まれるものであるため、シングルディスパッチのみがあるオブジェクト指向プログラミング言語でダブルディスパッチのようなふるまいを実現する手法が考えられている。ここでは一例としてRubyのものを示す。
たとえばRubyに複素数クラスを自作して追加したいとする。Rubyでは二項演算子 + なども、左辺にあるオブジェクトに対するメソッド呼び出しなので、次のようなソースコードへの対応は自然に実装できる。
これに対し、次のようにも書きたいわけだが、
もし何も仕掛けが無ければ、あらゆる既存の数値クラスについて、「複素数を引数にした場合」を追加する必要があり現実的ではない。しかし、Rubyにおける数値関係のクラスの、演算子に対応するメソッドは次のようにふるまうようになっていて、
追加したいクラス(たとえばここでは複素数クラス)に coerce というメソッドを一つ定義し、適切な値を返すようにすれば、任意の演算子に対して望んだような結果にできる。