2010-07-16 22 views
7

我写了访问者模式如下,但我不明白什么是单一和双重调度。 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方法的对象上。

谢谢。

+0

也许阅读这篇[文章](http://en.wikipedia.org/wiki/Multiple_dispatch)可以帮助你理解派遣 - 而不是它是如何在C++中实现的,但是概念 – 2010-07-16 08:37:56

回答

9

简而言之,单个分派是当一个方法对于一个参数的类型(包括隐含的this)是多态的。双派遣是两个参数的多态性。

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

[更新]我假定在你的例子,floppyDiskprocessorcomputer各自从一个共同的基类,它accept定义为一个虚拟方法继承。同样,visit*方法应该在equipmentVisitor中声明为虚拟,这应该有一些派生类与不同的visit*实现。 [/更新]

假设以上,accept是在两个thisequipmentVisitor多态性。软盘,处理器和计算机各有其自己的实现accept,所以当访问者呼叫accept时,根据被调用者的类型调度该cal。然后被叫方回叫访问者的类型特定访问方法,并根据访问者的实际类型调度此调用。

从理论上讲,也可以有三重,四重等调度,尽管我从来没有在实践中看到过这种调度(在自然界不支持双倍或更高调度的语言中,也就是 - 我似乎记得Smalltalk呢?)。使用C++和类似语言的Visitor进行双重调度本身已经相当令人难以置信,所以实现三倍或更高版本的调度将太复杂,不能在实际应用程序中使用。

+1

+ 1,不支持它的语言中的多派遣意味着手动书面方式所有的组合,并且随着派发的参数数目而呈指数增长,这是一个很好的理由来避免它。 – 2010-07-16 08:31:13

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