2010-08-31 7 views
8

Le modèle de visiteur est-il le moyen le plus rapide d'effectuer l'identification du type de paramètre de méthode (envoi direct sur un paramètre, pas la classe d'un membre) en C++? Je pourrais connaître la (les) méthode (s) exacte (s) que je veux invoquer sur des éléments du sous-type pas encore connu, donc invariablement faire un appel de méthode virtuelle supplémentaire comme V::visit(A *) dans A::accept(V &v) { v.visit(this); } est indésirable.Le modèle de visiteur est-il le moyen le plus rapide de différencier les types de paramètres en 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 

Je voudrais quelque chose fonctionnellement équivalent aux échelles suivantes, mais avec O (1) coût, ce qui est impossible avec AFAIK dynamic_cast <> ou typeid(), puisque std::type_info ne peut pas être un constexpr/commutable.

// 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; 
} 

Quelles sont mes options ici? Merci pour le conseil!

Édition: Modification de l'exemple de code pour acheminer les résultats via le champ, de sorte que plusieurs signatures ne soient pas nécessaires pour différents types de méthode. Merci, Maurice!

Décision finale: En plus de ne pas aimer le coût double expédition obligatoire du motif des visiteurs, je voulais aussi éviter le ballonnement d'interface de surcharge foo(), mais je ne pense pas qu'il y ait un modèle propre connu fais ceci. J'ai fini par faire des surcharges statiques et je l'ai appelé un jour. Quoi qu'il en soit, mon désir d'encapsuler une surcharge dans une fonction est probablement un objectif discutable au mieux. Merci, Maurice pour la réponse.

+0

pour les lecteurs après C++ 11: jetez un oeil à la bibliothèque Yorel Multimethod (qui est dans Boost maintenant) –

Répondre

3

En fait, les interfaces n'ont pas besoin d'être dupliquées. Les sous-classes du visiteur peuvent gérer les détails de l'opération. Dans votre cas:

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; 
    } 
} 

Ainsi, une seule méthode accepter() est nécessaire dans chaque classe. Toutes les alternatives au modèle de visiteur je peux penser impliquer une sorte de recherche d'exécution, ainsi oui, à mon humble avis, le modèle de visiteur est le chemin le plus rapide.

+0

Ah, bon point. Question intro et l'exemple de code mis à jour pour refléter cela. – Jeff

Questions connexes