Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/132.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 理解双重分派C++;_C++_Double Dispatch - Fatal编程技术网

C++ 理解双重分派C++;

C++ 理解双重分派C++;,c++,double-dispatch,C++,Double Dispatch,我试图了解双重分派是如何工作的。我创建了一个例子,其中一个怪物和一个来自抽象类生物的战士可以战斗。该类生物有方法“fight”,该方法在派生类中定义,在每个派生类中定义了战士与战士或怪物等战斗时会发生什么。我编写了以下代码: #include<iostream> using namespace std; class Monster; class Warrior; class Creature{ public: virtual void fight(Creature&

我试图了解双重分派是如何工作的。我创建了一个例子,其中一个怪物和一个来自抽象类生物的战士可以战斗。该类生物有方法“fight”,该方法在派生类中定义,在每个派生类中定义了战士与战士或怪物等战斗时会发生什么。我编写了以下代码:

#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);
}
#包括
使用名称空间std;
类怪物;
阶级战士;
阶级生物{
公众:
虚拟虚空战斗(生物&)=0;
};
职业怪物:公共生物{

虚空斗士(勇士和西部){cout如果你想这样做,你需要使用RTTI。你需要检查传入的东西的类型。一般来说,如果可以避免的话,这不是最好的设计模式。如果你想与两个对象交互,你通常需要使用另一个对象的标准接口。例如,你可以说bioter.attack(其他生物)和攻击可能会询问其他生物的防御,并基于此和它自己的统计信息向其他生物发布hp更新。

很明显,你的
生物类中确实没有
战斗谁
,所以你需要在那里声明它,并将其声明为
虚拟的

双重分派的工作方式是调用(假定
Warrior&w=…
,而不是
Warrior w
):

首先,虚拟机制将选择
Warrior::fight
而不是
Monster::fight
,然后重载机制将选择
Monster::fighthwho(Warrior&m)
而不是
Warrior::fighthwho(Warrior&m)
。请注意,如果您有:

Warrior w;
Monster m;
Creature& c1 = w;
Creature& c2 = m;
c1.fight(c2); // not w.fight(m)
因此,最终将被调用的方法将根据调用它的对象的类型和作为参数发送的对象的类型进行调度,即双重调度

<> P>另外,请注意,这可能不是最好的例子,因为您的类型是同一层次结构的成员。访问者设计模式是一个很好的例子,它是在不支持它作为第一类公民(即C++和派生:java,C……)/P>的语言中的双调度实现。
正如@CrazyCasta正确指出的那样,当您的类层次结构开始增长时,这种方法会变得更难维护,并且会导致方法数量激增,因此请仔细选择…

我对上述答案的贡献是提供了经过良好测试的示例,以澄清现实中的双重分派概念ode您将找到我如何自己实现的答案

#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);

}
#包括
使用名称空间std;
甲级;
A1类;
A2类;
B1类;
B2类;
B类{
公众:
//分派器函数到
虚空碰撞(常数A&A)常数=0;
//A类型的实际冲突逻辑B
虚空碰撞(常数A1&a)常数=0;
虚空碰撞(常数A2&a)常数=0;
};
甲级{
公众:
//调度程序函数到B
虚空碰撞(常数B&B)常数=0;
//类型为B的实际冲突逻辑A
虚空碰撞(常数B1和b)常数=0;
虚空碰撞(常数B2和b)常数=0;
};
A1类:公共A{
公众:
无效碰撞(常量B&B)常量{
//派往b
b、 碰撞(*此);
}
无效碰撞(常数B1和b)常数{

当我将这一行添加到类“生物:虚拟虚空战斗”中时,我得到了/tmp/cceFWViM.o:In function
bioter::bioter()”:ex12_10.cpp:(.text.zn8createurec2ev[zn8createurec5ev]+0xf):未定义的对生物的
vtable'/tmp/cceFWViM.o:(.rodata.ZTV7Warrior[vtable for Warrior]+0x18):未定义对
生物::格斗者(生物&')/tmp/cceFWViM.o:(.rodata.\u ZTV7Monster[vtable for Monster]+0x18):未定义对
生物::格斗者(生物&')/tmp/cceFWViM.o:(.rodata.\u ZTI7Warrior[typeinfo for Warrior]+0x10)的引用:未定义对`typeinfo for Creature`的引用您需要将其声明为纯虚拟或提供身体。如果我向生物添加“虚拟虚空格斗者(战士&)=0;虚拟虚空格斗者(怪物&)=0;”,则该引用有效。但是否可以实现而不在生物中命名怪物和战士?如果我添加“虚拟虚空格斗者(生物&)=0;”它不起作用不,这是不可能的,你需要战斗者(战士&)和战斗者(怪物&)在《生物》中,这就是为什么它会很快变得非常糟糕的原因。@CrazyCasta你当然是对的。我注意到缺少
=0
,并忽略了参数“完全双重分派”的要点是避免基于RTTI的显式类型选择。你的方法需要在基类中为你想要加入的每种类型的类指定一个抽象函数teract with(很可能是从基类派生的所有类型)这很快就变得非常丑陋。我完全同意——这就是为什么我不特别喜欢访问者模式,特别是当层次结构开始增长时,它很快变成混乱的。如果有一个抽象的抽象类,什么是更好的方法?我不知道C++中的双调度(以及派生语言)的更好的选择。因为你需要明确地提供所有的组合。你遵循哪本书/教程?
#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);

}