什么是单一和双重调度?

nic*_*las 9 c++ design-patterns double-dispatch visitor-pattern

我写了访客模式如下,但我不明白什么是单一和双重调度.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* );
Run Code Online (Sandbox Code Playgroud)

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

AFAIK,第一次调度发生在调用accept的对象上,第二次调度发生在调用visit方法的对象上.

谢谢.

Pét*_*rök 9

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

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

[更新]我假定在你的例子,floppyDisk,processorcomputer各自从一个共同的基类定义继承accept作为虚拟方法.类似地,visit*应该将方法声明为virtual in equipmentVisitor,其中应该有一些具有不同visit*实现的派生类.[/更新]

假设上面的,accept是在两个多态thisequipmentVisitor.floppydisk,处理器和计算机都有自己的实现accept,因此当访问者调用时accept,将根据被调用者的类型调度cal.然后被叫方回叫访问者类型特定的访问方法,并根据访问者的实际类型调度此调用.

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

  • +1,在本身不支持它的语言中进行多次分派意味着手动编写所有组合,并且随着要发送的参数数量呈指数增长,这是尝试避免它的一个很好的理由. (3认同)

Gor*_*pik 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
Run Code Online (Sandbox Code Playgroud)

现在,想象一下你在某些函数中有这段代码:

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

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

总结一下:

  • 第一个调度调用accept()适当的类
  • 第二个调度在第一个调度选择的类上调用适当的函数