2010-07-16 24 views
7

he escrito el patrón de visitante de la siguiente manera, pero no entiendo qué es el envío simple y doble. AFAIK, el único despacho es invocar un método basado en el tipo de llamada donde el doble despacho invoca un método basado en el tipo de llamante y el tipo de argumento.¿Qué es el envío simple y doble?

Supongo que el doble envío se produce en la jerarquía de una sola clase, pero ¿por qué la clase de visitante tiene dos jerarquías de clase pero todavía se considera como despacho doble.

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

Explique utilizando el código de ejemplo que proporcioné.

AFAIK, el primer envío se produce en el objeto que invoca la aceptación y el segundo envío se produce en el objeto que invoca el método de visita.

Gracias.

+0

Tal vez la lectura de este [artículo ] (http://en.wikipedia.org/wiki/Multiple_dispatch) puede ayudarlo a entender el envío, no cómo se implementa en C++, pero el concepto –

Respuesta

9

En resumen, el envío único se produce cuando un método es polimórfico en el tipo de un parámetro (incluido el implícito this). El envío doble es polimorfismo en dos parámetros.

El ejemplo típico para el primero es un método virtual estándar, que es polimórfico en el tipo del objeto que lo contiene. Y el segundo se puede implementar a través del patrón Visitor.

[actualización] Asumo que en su ejemplo, floppyDisk, processor y computer cada heredan de una clase base común que define accept como un método virtual. Del mismo modo, los métodos visit* deben declararse virtuales en equipmentVisitor, que deberían tener algunas clases derivadas con diferentes implementaciones de visit*. [/ actualización]

Suponiendo que el anterior, accept es polimórfico en tanto this y equipmentVisitor. El floppydisk, el procesador y la computadora tienen cada uno su propia implementación de accept, de modo que cuando el visitante llama al accept, la llamada se envía según el tipo de destinatario. Luego, el llamado vuelve a llamar al método de visita específica de tipo de visitante, y esta llamada se envía según el tipo de visitante real.

En teoría, puede haber envío triple, cuádruple, etc., aunque nunca he visto esto implementado en la práctica (en idiomas que no admiten envíos dobles y superiores por naturaleza, es decir, me parece recordar que Smalltalk ¿hace?). El doble despacho utilizando Visitor en C++ y en lenguajes similares ya es bastante abrumador en sí mismo, por lo que la implementación de despachos triples y superiores sería simplemente demasiado complicado para ser utilizado en aplicaciones reales.

+1

+1, el despacho múltiple en idiomas que no lo admiten de forma nativa implican de forma manual escribiendo todas las combinaciones, y eso crece exponencialmente con la cantidad de argumentos para enviar, que es una buena razón para tratar de evitarlo. –

6

En su ejemplo, falta lo básico del mecanismo: herencia y virtualidad. Supongamos que la siguiente jerarquía de clases, además de su código:

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 

Ahora, imagine que tiene este pedazo de código en alguna función:

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

Gracias a la doble mecanismo de despacho, esta última línea permite cualquier equipmentVisited para aceptar cualquier equipmentVisitor, sin importar cuáles sean sus tipos estáticos reales. Eventualmente, se llamará a la función correcta para la clase correcta.

En resumen:

  • El primer envío llama accept() en la clase apropiada
  • La segunda expedición llama a la función apropiada de la clase seleccionada por el primer envío
Cuestiones relacionadas