2010-07-16 6 views
7

Ich habe das Besuchermuster wie folgt geschrieben, aber ich verstehe nicht, was Einzel- und Doppelversand ist. AFAIK, einzelne Versendung ruft eine Methode auf, die auf dem Aufruftyp basiert, bei dem die doppelte Versendung eine Methode basierend auf dem Aufruftyp und dem Argumenttyp aufruft.Was ist Single und Double Dispatch?

Ich denke, Doppelversand ist in der einzelnen Klassenhierarchie passieren, aber warum Besucher Klasse hat zwei Klassenhierarchie, aber es gilt immer noch als Doppelversand.

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

Bitte erläutern Sie anhand des von mir bereitgestellten Beispielcodes.

AFAIK, die erste Dispatch erfolgt auf Objekt, wer die Annahme aufrufen und zweiten Dispatch geschieht auf Objekt, die die Visit-Methode aufrufen.

Danke.

+0

Vielleicht Lesen dieses [Artikel ] (http://en.wikipedia.org/wiki/Multiple_dispatch) kann Ihnen helfen zu verstehen, Versand - nicht wie es in C++ implementiert ist, aber das Konzept –

Antwort

9

Kurz gesagt, Single-Dispatch ist, wenn eine Methode polymorph ist auf den Typ eines Parameters (einschließlich der impliziten this). Double Dispatch ist Polymorphie auf zwei Parameter.

Das typische Beispiel für das erste ist eine virtuelle Standardmethode, die für den Typ des enthaltenden Objekts polymorph ist. Und der zweite kann über das Besuchermuster implementiert werden.

[update] Ich gehe davon aus, dass in Ihrem Beispiel floppyDisk, processor und computer jeweils von einer gemeinsamen Basisklasse erben, die accept als virtuelle Methode definiert. In ähnlicher Weise sollten die visit* Methoden in equipmentVisitor virtuell deklariert werden, die einige abgeleitete Klassen mit verschiedenen visit* Implementierungen haben sollten. [/ Update]

die oben Angenommen, ist accept sowohl polymorphe auf this und equipmentVisitor. Der Floppydisk, der Prozessor und der Computer haben jeweils ihre eigene Implementierung von accept. Wenn der Besucher accept aufruft, wird der cal basierend auf dem Typ des Angerufenen gesendet. Dann ruft der Angerufene die typspezifische Besuchsmethode des Besuchers zurück, und dieser Anruf wird basierend auf dem tatsächlichen Typ des Besuchers ausgelöst.

In der Theorie kann es dreifache, vierfache usw. Sendung auch geben, obwohl ich nie gesehen habe, dass in der Praxis (in Sprachen, die doppelte und höhere Versendungen von Natur aus nicht unterstützen, das heißt - ich denke, dass Smalltalk zu erinnern geht das?). Der doppelte Versand mit dem Besucher in C++ und ähnlichen Sprachen ist bereits an sich schon verblüffend, so dass die Implementierung von dreifachen und höheren Versendungen einfach zu kompliziert wäre, um in realen Anwendungen verwendet zu werden.

+1

+1, mehrere Versand in Sprachen, die nicht nativ unterstützen es manuell implizieren schreiben alle Kombinationen, und das wächst exponentiell mit der Anzahl der Argumente, auf die zu versenden ist, was ein guter Grund ist, es zu vermeiden. –

6

In Ihrem Beispiel fehlen Ihnen die Grundlagen des Mechanismus: Vererbung und Virtualität. Lassen Sie sich die folgende Klassenhierarchie übernehmen, zusätzlich zu Ihrem Code:

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 

Nun stellen Sie dieses Stück Code haben in irgendeiner Funktion:

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

Dank des Doppel-Ausgabe-Mechanismus, diese letzte Zeile erlaubt equipmentVisited jede equipmentVisitor zu akzeptieren, egal was ihre tatsächlichen statischen Typen sind. Schließlich wird die richtige Funktion für die richtige Klasse aufgerufen.

Fassen wir zusammen:

  • Der erste Dispatch accept() auf die entsprechende Klasse ruft
  • Die zweite Dispatch ruft die entsprechende Funktion auf der von der ersten Versendung ausgewählten Klasse
Verwandte Themen