理解双调度C ++ [英] Understanding double dispatch C++

查看:121
本文介绍了理解双调度C ++的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试了解双重调度的工作原理。我创建了一个例子,一个怪物和一个来自抽象类Creature的战士可以战斗。类Creature有方法打斗,它在派生类中定义,并且在每个派生类中定义如果战士与战士或怪物等战斗会发生什么。我写了以下代码:

 #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< }
void fightwho(Monster& m){cout<<Monster versus Monster<< endl; }
public:
void fight(Creature& c){c.fightwho(* this);}
};

class战士:公开生物{
void fightwho(warrior& w){cout<<<Warrior vs Warrior< }
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:在成员函数'virtual void Monster :: fight(Creature&)':ex12_10.cpp:17:30:error:'class Creature'没有成员名为'fightwho'



ex12_10.cpp:在成员函数'virtual void Warrior :: fight(Creature&)':ex12_10.cpp:24:29:error:'class Creature'has没有名为fightwho的成员



但我不知道如何从这里继续...请帮助。

生物中声明 fightwho c $ c>类,所以你需要声明它,并声明为 virtual



工作方式为调用(这假设 Warrior& w = ... ,而不是 Warrior w ): / p>

  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)

因此,最终将调用的方法将被调度根据您调用它的对象的类型和作为参数发送的对象的类型,即 double dispatch



这可能不是最好的示例,因为您的类型是同一层次结构的成员。访问者设计模式是不支持它作为第一类公民(即C ++和派生:Java,C#...)的语言中的双调度实现的一个很好的例子。



因为@CrazyCasta正确地注意到,当你的类层次结构开始增长时,这种方法变得难以维护,并且可能导致许多方法的爆炸,所以仔细选择...


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.

解决方案

Well, obviously, you really don't have fightwho declared in your Creature class, so you need to declare it there, and declare it as virtual.

Double dispatch works in a way that for call (this assumes Warrior& w = ..., not Warrior w):

w.fight(m);

First the virtual mechanism will chose Warrior::fight instead of Monster::fight and then the overloading mechanism will pick Monster::fightwho(Warrior& m) instead of Warrior::fightwho(Warrior& m). Note that it would make more sense if you would have:

Warrior w;
Monster m;
Creature& c1 = w;
Creature& c2 = m;
c1.fight(c2); // not w.fight(m)

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...

这篇关于理解双调度C ++的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆