2010-08-31 15 views
8

¿Es el patrón de visitante la forma más rápida de lograr la identificación del tipo de parámetro del método (efectivamente envío único en un parámetro, no una clase de miembro) en C++? Puede que sepa el (los) método (s) exacto (s) que quiero invocar en los elementos del subtipo aún no conocido, por lo que invariablemente hacer una llamada al método virtual adicional como V::visit(A *) en A::accept(V &v) { v.visit(this); } es indeseable.¿Es el patrón de visitante la forma más rápida de diferenciar tipos de parámetros 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 

me gustaría algo funcionalmente equivalente a los siguientes, pero con O (1) costo, que yo sepa no es posible con dynamic_cast <> o typeid() escaleras, ya que std::type_info no puede haber un constexpr/conmutable.

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

¿Cuáles son mis opciones aquí? ¡Gracias por el consejo!

Editar: Se modificó el código de muestra para los resultados de alimentación a través del campo, por lo que no se necesitan múltiples firmas para diferentes tipos de métodos. Gracias, Maurice!

Decisión final: Además de que no le gustaba el costo de envío de doble obligatoria del patrón del visitante, yo también quería evitar los excesos de interfaz de sobrecargar foo(), pero no creo que hay un patrón conocido limpia a hacer esto. Terminé haciendo sobrecargas estáticas rectas y lo llamé un día. De todos modos, mi deseo de encapsular la sobrecarga dentro de una función es probablemente un objetivo cuestionable en el mejor de los casos. Gracias, Maurice por la respuesta.

+0

para lectores después de C++ 11: eche un vistazo a la biblioteca Yorel Multimethod (que está en Boost ahora) –

Respuesta

3

De hecho, las interfaces no necesitan ser duplicadas. Las subclases del visitante pueden manejar los detalles de la operación. En su caso:

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

Por lo tanto, solo se necesita un método accept() en cada clase.

Todas las alternativas al patrón de visitante que puedo pensar implican algún tipo de búsqueda en tiempo de ejecución, así que sí, en mi humilde opinión, el patrón de visitante es la manera más rápida.

+0

Ah, buen punto. Introducción de pregunta y código de muestra actualizado para reflejar esto. – Jeff

Cuestiones relacionadas