I try to understand how double dispatch works. I created an example where a monster and a warrior derived from the abstract class Creature could fight. The class Creature has method "fight", which is defined in derived classes, and in each derived class is defined what happens if warrior fights with warrior or with monster etc. I wrote the following code:
#include<iostream>
using namespace std;
class Monster;
class Warrior;
class Creature{
public:
virtual void fight(Creature&) =0;
};
class Monster: public Creature{
void fightwho(Warrior& w) {cout<<"Monster versus Warrior"<<endl; }
void fightwho(Monster& m) {cout<<"Monster versus Monster"<<endl; }
public:
void fight(Creature& c) {c.fightwho(*this);}
};
class Warrior: public Creature{
void fightwho(Warrior& w) {cout<<"Warrior versus Warrior"<<endl; }
void fightwho(Monster& m) {cout<<"Monster versus Warrior"<<endl; }
public:
void fight(Creature& c) {c.fightwho(*this);}
};
int main()
{
Warrior w;
Monster m;
w.fight(m);
}
This results in compiler error, which I foresee:
ex12_10.cpp: In member function ‘virtual void Monster::fight(Creature&)’: ex12_10.cpp:17:30: error: ‘class Creature’ has no member named ‘fightwho’
ex12_10.cpp: In member function ‘virtual void Warrior::fight(Creature&)’: ex12_10.cpp:24:29: error: ‘class Creature’ has no member named ‘fightwho’
But I don't know how to proceed from here... Please help.
If you want to do this you will need to use RTTI. You will need to check the type of the thing being passed in. In general this is not the best design pattern to be used if you can avoid it. If you want to interact two objects you generally want to use the standard interface of another. For instance you might say creature.attack(other_creature) and attack might query the defense of the other creature, and based on that and it's own stats post an hp update to the other_creature.
Well, obviously, you really don't have
fightwho
declared in yourCreature
class, so you need to declare it there, and declare it asvirtual
.Double dispatch works in a way that for call (this assumes
Warrior& w = ...
, notWarrior w
):First the virtual mechanism will chose
Warrior::fight
instead ofMonster::fight
and then the overloading mechanism will pickMonster::fightwho(Warrior& m)
instead ofWarrior::fightwho(Warrior& m)
. Note that it would make more sense if you would have:Therefore, the method which will eventually be called will be dispatched according to type of the object on which you call it and type of the object sent as argument, i.e. double dispatch
Additionally, please note that this might not be the best example as your types are members of the same hierarchy. Visitor design pattern is a good example of double dispatch implementations in languages which don't support it as first class citizens (i.e. C++ and derivatives: Java, C#...)
As @CrazyCasta correctly notes, when your class hierarchy starts to grow, this approach becomes much harder to maintain and can result in explosion of number of methods, so choose carefully...
My contribution to above answers is providing well-tested example in order to clarify double dispatch concept in reality. If you review the below code you will find the answer of how can I implement by myself.