我试着去了解如何双重分派工作。 我创建了一个例子,其中一个怪物,并从抽象类生物来源的战士可以战斗。 该类生物具有法“打架”,这是在派生类中定义,并在每个派生类中的定义,如果战士用武士或怪物等我写了下面的代码战斗会发生什么:
#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);
}
这将导致编译器错误,我预见到:
ex12_10.cpp:在成员函数“虚拟无效妖怪战斗::(生物&)”:ex12_10.cpp:17:30:错误:“类生物”没有名为“fightwho”构件
ex12_10.cpp:在成员函数“虚拟战士空隙::斗争(生物&)”:ex12_10.cpp:24:29:错误:“类生物”没有名为“fightwho”构件
但我不知道如何从这里出发......请帮助。
嗯,很明显,你真的没有fightwho
在你宣称的Creature
类,所以您需要在那里声明它,并宣布它作为virtual
。
双调度工作的方式,呼叫(假设Warrior& w = ...
,不是Warrior w
):
w.fight(m);
第一虚拟机制将选择Warrior::fight
代替Monster::fight
然后超载机构将选择Monster::fightwho(Warrior& m)
代替Warrior::fightwho(Warrior& m)
请注意,它会更有意义,如果你会:
Warrior w;
Monster m;
Creature& c1 = w;
Creature& c2 = m;
c1.fight(c2); // not w.fight(m)
因此,这将最终被调用的方法将根据类型上你怎么称呼它,并将其作为参数的对象类型的对象被派遣,即双重分派
此外,请注意,这可能不是最好的例子作为你的类型相同层次的成员。 Visitor设计模式是双重分派实施的语言很好的例子,它不支持它作为一等公民(即C ++及衍生物:Java和C#...)
作为@CrazyCasta正确地指出,当你的类层次结构开始增长,这种方法变得更难维持,并可能导致的方法数量的爆炸,因此请谨慎选择...
我上面的回答贡献,以澄清在现实双重分派概念提供完善的测试实例。 如果您查看下面的代码,你会发现我怎么能自己实现了答案。
#include <iostream>
using namespace std;
class A;
class A1;
class A2;
class B1;
class B2;
class B {
public:
// dispatcher function to A
virtual void collide(const A& a) const = 0;
// actual collision logic B with types of A
virtual void collide(const A1& a) const = 0;
virtual void collide(const A2& a) const = 0;
};
class A {
public:
// dispatcher function to B
virtual void collide(const B& b) const = 0;
// actual collision logic A with types of B
virtual void collide(const B1& b) const = 0;
virtual void collide(const B2& b) const = 0;
};
class A1 : public A {
public:
void collide(const B& b) const {
// dispatch to b
b.collide(*this);
}
void collide(const B1& b) const {
cout << "collision with B1 and A1" << endl;
}
void collide(const B2& b) const {
cout << "collision with B2 and A1" << endl;
}
};
class A2 : public A {
public:
void collide(const B& b) const {
// dispatch to a
b.collide(*this);
}
void collide(const B1& b) const {
cout << "collision with B1 and A2" << endl;
}
void collide(const B2& b) const {
cout << "collision with B2 and A2" << endl;
}
};
class B1 : public B {
public:
void collide(const A& b) const {
b.collide(*this);
}
void collide(const A1& b) const {
cout << "collision with A1 Bnd B1" << endl;
}
void collide(const A2& b) const {
cout << "collision with A2 Bnd B1" << endl;
}
};
class B2 : public B {
public:
void collide(const A& a) const {
a.collide(*this);
}
void collide(const A1& a) const {
cout << "collision with A1 Bnd B2" << endl;
}
void collide(const A2& a) const {
cout << "collision with A2 Bnd B2" << endl;
}
};
int main() {
A* a = new A1();
B* b = new B2();
// first dispatch is done by polymorphism ( a is resolved as a A1 )
// second dispatch is done in collide function by the function overloading
// ( in collide function we are sending A1 to collide function of B )
a->collide(*b);
}
如果要做到这一点,你需要使用RTTI。 您将需要检查的传递的东西的类型。一般来说,这是不被使用,如果你能避免它最好的设计模式。 如果你想交流的两个对象,你一般要使用另一人的标准接口。 例如,你可能会说creature.attack(other_creature)和攻击可能查询其他生物的防御,并基于该和它自己的统计数据发布的HP更新到other_creature。