11

我已经编写了如下的访问者模式,但我不明白什么是单次和双次调度。AFAIK,单调度是调用基于调用者类型的方法,而双调度是调用基于调用者类型和参数类型的方法。

我猜双重分派发生在单类层次结构中,但为什么访问者类有两个类层次结构,但它仍然被认为是双重分派。

void floppyDisk::accept(equipmentVisitor* visitor)
{
 visitor->visitFloppyDisk(this);
}

void processor::accept(equipmentVisitor* visitor)
{
 visitor->visitProcessor(this);
}

void computer::accept(equipmentVisitor* visitor)
{
 BOOST_FOREACH(equipment* anEquip, cont)
 {
  anEquip->accept(visitor);
 }

 visitor->visitComputer(this);
}

void visitFloppyDisk(floppyDisk* );
void visitProcessor(processor* );
void visitComputer(computer* );

请使用我提供的示例代码进行解释。

AFAIK,第一次调度发生在调用接受的对象上,第二次调度发生在调用访问方法的对象上。

谢谢。

4

2 回答 2

13

简而言之,单次调度是指一个方法在一个参数的类型上是多态的(包括隐式this)。双分派是两个参数的多态性。

第一个的典型示例是标准虚方法,它在包含对象的类型上是多态的。第二个可以通过访问者模式实现。

[更新]我假设在您的示例中,floppyDisk,processorcomputer每个都继承自一个定义accept为虚拟方法的公共基类。同样,这些visit*方法应该被声明为 virtual in equipmentVisitor,其中应该有一些具有不同visit*实现的派生类。[/更新]

假设上述情况,在和accept上都是多态的。软盘、处理器和计算机都有自己的实现,所以当访问者调用时,会根据被调用者的类型调度cal。然后被调用者回调访问者特定类型的访问方法,这个调用根据访问者的实际类型进行调度。thisequipmentVisitoracceptaccept

理论上,也可以有三重、四重等调度,尽管我从未在实践中看到过这种实现(在本质上不支持双重和更高调度的语言中,也就是说 - 我似乎记得 Smalltalk 支持?)。在 C++ 和类似语言中使用 Visitor 的双重分派本身已经非常令人难以置信,因此三重分派和更高级别的分派的实现太复杂而无法在实际应用程序中使用。

于 2010-07-16T07:49:13.553 回答
7

在您的示例中,您缺少机制的基础知识:继承和虚拟性。除了您的代码之外,让我们假设以下类层次结构:

class equipmentVisited
{
  virtual void accept(equipmentVisitor* visitor) = 0;
}

class floppyDisk : public equipmentVisited
{
  virtual void accept(equipmentVisitor* visitor);
}

class processor : public equipmentVisited
{
  virtual void accept(equipmentVisitor* visitor);
}

class computer : public equipmentVisited
{
  virtual void accept(equipmentVisitor* visitor);
}

class equipmentVisitor
{
  virtual void visitFloppyDisk(floppyDisk* );
  virtual void visitProcessor(processor* );
  virtual void visitComputer(computer* );
}

// Some additional classes inheriting from equipmentVisitor would be here

现在,假设您在某个函数中有这段代码:

equipmentVisited* visited;
equipmentVisitor* visitor;
// ...
// Here you initialise visited and visitor in any convenient way
// ...
visited->accept(visitor);

由于双重调度机制,最后一行允许 anyequipmentVisited接受 any equipmentVisitor,无论它们的实际静态类型是什么。最终,将为正确的类调用正确的函数。

总结一下:

  • 第一次调度调用accept()适当的类
  • 第二个调度调用第一个调度选择的类上的适当函数
于 2010-07-16T08:03:58.437 回答