47

我试图了解什么是多次调度。我阅读了很多不同的文本,但我仍然不知道多重调度是什么以及它有什么好处。也许我缺少的是使用多次调度的一段代码。拜托,你能用 C++ 编写一小段代码,使用多次调度,这样我就可以看到它不能正确编译/运行,因为 C++ 只有一次调度?我需要看到区别。谢谢。

4

3 回答 3

84

多调度是根据传递给函数调用的参数的运行时类型来选择调用哪个版本的函数的能力。

这是一个在 C++ 中无法正常工作的示例(未经测试):

class A { };
class B : public A { };
class C : public A { }


class Foo
{
  virtual void MyFn(A* arg1, A* arg2) { printf("A,A\n"); }
  virtual void MyFn(B* arg1, B* arg2) { printf("B,B\n"); }
  virtual void MyFn(C* arg1, B* arg2) { printf("C,B\n"); }
  virtual void MyFn(B* arg1, C* arg2) { printf("B,C\n"); }
  virtual void MyFn(C* arg1, C* arg2) { printf("C,C\n"); }
};

void CallMyFn(A* arg1, A* arg2)
{
  // ideally, with multi-dispatch, at this point the correct MyFn() 
  // would be called, based on the RUNTIME type of arg1 and arg2
  pFoo->MyFn(arg1, arg2);
}

...

A* arg1 = new B();
A* arg2 = new C();
// Using multi-dispatch this would print "B,C"... but because C++ only
// uses single-dispatch it will print out "A,A"
CallMyFn(arg1, arg2);
于 2009-11-17T15:22:25.210 回答
24

多重分派是指执行的函数取决于多个对象的运行时类型。

C++ 具有单一调度,因为当您使用虚函数时,实际运行的函数仅取决于 -> 或 . 操作员。

我正在努力想一个真正的多分派编程案例。也许在一个不同角色互相战斗的游戏中。

void Fight(Opponent& opponent1, Opponent& opponent2);

战斗的获胜者可能取决于双方对手的特征,因此您可能希望此调用调度到以下之一,具体取决于两个参数的运行时类型:

void Fight(Elephant& elephant, Mouse& mouse)
{
    mouse.Scare(elephant);
}

void Fight(Ninja& ninja, Mouse& mouse)
{
    ninja.KarateChop(mouse);
}

void Fight(Cat& cat, Mouse& mouse)
{
    cat.Catch(mouse);
}

void Fight(Ninja& ninja, Elephant& elephant)
{
    elephant.Trample(ninja);
}

// Etc.

函数的作用取决于两个参数的类型,而不仅仅是一个。在 C++ 中,您可能必须将其编写为一些虚函数。将根据一个参数(this 指针)选择一个虚函数。然后,虚函数可能需要包含一个开关或一些东西来对另一个参数做一些特定的事情。

于 2009-11-17T15:22:38.490 回答
3

单次调度中,执行的函数仅取决于对象类型。在 双重分派中,执行的函数取决于对象类型和参数。

在下面的示例中,该函数Area()使用单次调度调用,并且Intersect()依赖于双调度,因为它采用 Shape 参数。

class Circle;
class Rectangle;
class Shape
{
    virtual double Area() = 0; // Single dispatch

    // ...
    virtual double Intersect(const Shape& s) = 0; // double dispatch, take a Shape argument
    virtual double Intersect(const Circle& s) = 0; 
    virtual double Intersect(const Rectangle& s) = 0; 
};

struct Circle : public Shape
{
    virtual double Area() { return /* pi*r*r */; }

    virtual double Intersect(const Shape& s); 
    { return s.Intersect(*this)  ; }
    virtual double Intersect(const Circle& s); 
    { /*circle-circle*/ }
    virtual double Intersect(const Rectangle& s); 
    { /*circle-rectangle*/ }
};

该示例基于本文

于 2009-11-17T15:25:37.890 回答