什么是单一和双重调度?

时间:2010-07-16 07:34:11

标签: c++ design-patterns visitor-pattern double-dispatch

我写了访客模式如下,但我不明白什么是单一和双重调度。 AFAIK,单个调度是基于调用者类型调用一个方法,其中double dispatch根据调用者类型和参数类型调用方法。

我认为双重调度是在单个类层次结构中发生的,但为什么访问者类有两个类层次结构但它仍被视为双重调度。

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,第一次调度发生在调用accept的对象上,第二次调度发生在调用visit方法的对象上。

感谢。

2 个答案:

答案 0 :(得分:9)

简而言之,单一调度是指一个方法对一个参数的类型(包括隐式this)具有多态性。双重调度是两个参数的多态性。

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

[更新] 我假设在您的示例中,floppyDiskprocessorcomputer都是从定义{{1}的公共基类继承的}作为虚拟方法。同样,accept方法应该在visit*中声明为虚拟,其中应该有一些具有不同equipmentVisitor实现的派生类。的 [/更新]

假设上述情况,visit*accept上的this都是多态的。 floppydisk,处理器和计算机都有自己的equipmentVisitor实现,因此当访问者调用accept时,将根据被调用者的类型调度cal。然后被叫方回拨访问者类型特定的访问方法,并根据访问者的实际类型调度此调用。

理论上也可以有三重,四重等调度,虽然我从未见过这在实践中实现过(在语言中不支持双重和更高级别的调度,也就是说 - 我似乎记得Smalltalk确实?)。使用C ++和类似语言的Visitor进行双重调度本身已经非常令人难以置信,因此三次和更高级别调度的实现过于复杂,无法在实际应用中使用。

答案 1 :(得分:6)

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

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

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

总结:

  • 第一个调度在相应的类
  • 上调用accept()
  • 第二个调度调用第一个调度所选类的相应函数