2010-08-31 15 views
8

Il pattern Visitor è il modo più veloce per eseguire l'identificazione del tipo di parametro del metodo (in pratica un singolo invio su un parametro, non una classe membro) in C++? Potrei conoscere il metodo esatto che voglio invocare su elementi del sottotipo non ancora conosciuto, quindi invariabilmente effettuare una chiamata al metodo virtuale addizionale come V::visit(A *) in A::accept(V &v) { v.visit(this); } non è auspicabile.Il pattern Visitor è il modo più veloce per differenziare i tipi di parametri in C++?

// Is the Visitor pattern recommended here? (E inherits D inherits B.) 
class Foo { 
public: 
    virtual void visit(B *) { result = 3; } 
    virtual void visit(D *) { result = 4; } 
    virtual void visit(E *) { result = 5; } 
private: 
    int result; 
}; // class Foo 

// Need to add generic interface to B and its children ... 
class B { 
public: 
    virtual void accept(class Foo &f) { f.visit(this); } 
}; // class B 

Mi piacerebbe qualcosa i seguenti, ma con O (1) il costo, che non è per quanto ne so possibile con dynamic_cast <> o typeid() scale funzionalmente equivalenti, dal momento che std::type_info non può essere una constexpr/commutabile.

// O(n) search cost might get nasty with bigger hierarchies. 
int foo(B *b) { 
    if (typeid(b) == typeid(B *)) { return 1; } 
    if (typeid(b) == typeid(D *)) { return 2; } 
    if (typeid(b) == typeid(E *)) { return 3; } 
    return -1; 
} 

Quali sono le mie opzioni qui? Grazie per il consiglio!

Modifica: Modifica codice di esempio per alimentare i risultati attraverso il campo, in modo tale che non siano necessarie più firme per diversi tipi di metodo. Grazie, Maurizio!

decisione finale: Oltre a non gradire il costo obbligatoria invio doppio del modello Visitatore, ho anche voluto evitare la pesantezza dell'interfaccia di sovraccarico foo(), ma non credo che ci sia un disegno pulito noto a Fai questo. Ho finito per fare solo drastici sovraccarichi statici e l'ho chiamato un giorno. Ad ogni modo, il mio voler incapsulare il sovraccarico all'interno di una funzione è probabilmente un obiettivo discutibile al meglio. Grazie, Maurice per la risposta.

+0

per i lettori dopo C++ 11: dai un'occhiata alla libreria Yorel Multimethod (che ora è in Boost) –

risposta

3

Infatti, le interfacce non devono essere duplicate. Le sottoclassi del visitatore possono gestire i dettagli dell'operazione. Nel tuo caso: il metodo

class Visitor { 
    virtual void visit(B*) = 0; 
    virtual void visit(D*) = 0; 
    virtual void visit(E*) = 0; 
} 

class Foo: public Visitor { 
private: 
    int result; 
public: 
    void visit(B*) { result = 3; } 
    void visit(D*) { result = 4; } 
    void visit(E*) { result = 5; } 
    int apply(A* a) { 
     a->accept(this); 
     return result; 
    } 
} 

Quindi, solo una accept() è necessaria in ogni classe.

Tutte le alternative al modello di visitatore Posso pensare di coinvolgere qualche tipo di ricerca in fase di esecuzione, quindi sì, IMHO, il modello di visitatore è il modo più veloce.

+0

Ah, buon punto. Intro delle domande e codice di esempio aggiornato per riflettere questo. – Jeff