2009-12-23 20 views
5

Estoy tratando de tener el método void run(string method) que ejecutará método en esa clase. Por ejemplo:¿Cómo puedo llamar a un método dado solo su nombre?

class Foo { 
    public: 
    void run(string method) { 
     // this method calls method *method* from this class 
    } 
    void bar() { 
     printf("Function bar\n"); 
    } 
    void foo2() { 
     printf("Function foo2\n"); 
    } 
} 

Foo foo; 

int main(void) { 
    foo.run("bar"); 
    foo.run("foo2"); 
} 

este imprimiría:

Function bar 
Function foo2 

Gracias! :)

+1

¿Qué está tratando de lograr? –

Respuesta

15

Puede crear un std::map que asigna cadenas a punteros de función de miembro, siempre que todas las funciones que desee llamar tengan la misma firma.

El mapa se declararía como:

std::map<std::string, void(Foo::*)()> function_map; 
+2

de lo contrario, 'if() {} else if() {} else if() {} else {}' todavía está aquí ;-) –

+2

si tuviera que ir por esta solución, sin embargo, la convertiría en una estática mapa: nunca posponga hasta el tiempo de ejecución lo que puede hacer en tiempo de compilación. –

2

Usted puede hacer un mapa de los punteros de función miembro, con la clave del mapa es el nombre de la función. Sin embargo, los punteros a las funciones de miembro son un poco difíciles de trabajar.

http://www.parashift.com/c++-faq-lite/pointers-to-members.html

La manera más fácil es hacer un montón de if-then-else bloques en función de su run llamar a la función apropiada.

6

La solución de mapa ya mencionada funcionaría para listas fijas de funciones, pero no creo que haya una manera de introspección como esta en general en C++. Es decir, no puede tener una función void perform(string methodName) que diga "¿Tengo un método llamado methodName? De ser así, llámelo".

+0

Sí, C++ no se parece en nada a Java en este aspecto. – Omnifarious

+0

... también no como Objective-C, Python, Perl, JavaScript, Ruby, C# ... – benzado

+0

@benzado: Objective-C es completamente diferente, está enviando un mensaje. Si el objeto sabe cómo reaccionar al mensaje, ejecutará el código. Python/Perl/Javascript: todos los objetos son solo mapas, por lo que los métodos son solo objetos que se adjuntan como valor. C# y Java son diferentes en ese tipo de introspección (AKA reflexión) lo que le permite encontrar los métodos por nombre y luego llamarlos. –

1

Como han dicho los otros carteles, debe hacer esto a mano en C++, ya que el lenguaje no tiene incorporado Reflection.

Idiomas como C# y Java tienen esto incorporado así que puede valer la pena repensar el idioma que elijas, dependiendo de lo que necesites.

-3

No puede hacerlo sin RTTI o algún tipo de mapa. O una solución como esta:

 
class Foo { 
    public: 
    void run(string method) { 
     bar(method); 
     foo2(method); 
    // ... more methods here 
    } 
    void bar(string method) { 
     if (method != "bar") return; 
     printf("Function bar\n"); 
    } 
    void foo2(string method) { 
     if (method != "foo2") return; 
     printf("Function foo2\n"); 
    } 
} 

Foo foo; 

int main(void) { 
    foo.run('bar'); 
    foo.run('foo2'); 
}

esto le dará el mismo resultado que quería

+2

Su solución sugerida es sencillamente horrible. Es ineficiente, porque para n métodos cada llamada a 'ejecutar' dará como resultado n llamadas a métodos sin importar qué. Tampoco se puede mantener, porque la lógica para asignar un nombre a un método se distribuye entre los métodos. – benzado

9

Como otros han señalado, C++ no hacer este tipo de reflexión fuera de la caja (y las probabilidades son que probablemente no sea lo que quieres hacer.)

Pero mencionaré que existen algunos preprocesadores que implementan esta funcionalidad para un subconjunto de clases y métodos. El moc de Qt es un ejemplo de esto, y es parte de la mecánica de señal/tragamonedas. Aviso method() y methodCount() en el QMetaObject ...

La forma Qt hace esto es mediante la inyección de una herramienta en su proceso de construcción que hace que las tablas y los compila con el resto de su código. Es todo lo que podría haber escrito a mano, no una función de idioma.

3

Aunque las respuestas anteriores son para su solución, su solución no parece ser la correcta para su problema.

Tengo dos sugerencias: 1) Crear una mejor clase base abstracta o 2) Usar una clase base para los funtores (objetos funcionales).Veamos con más detalle ...

Dado un proyecto de simular el conjunto de instrucciones de un procesador, podemos simular la ejecución con:

struct Instruction_Interface 
{ 
    virtual void execute(void) = 0; 
}; 

typedef std::vector<Instruction_Interface *> Instruction_Container; 

//... 
Instruction_Container::iterator iter; 
Instruction_Container program_instructions; 
//... 
for (iter = program_instructions.begin(); 
    iter != program_instructions.end(); 
    ++iter) 
{ 
    (*iter)->execute(); // Execute the instruction; 
} 

Esto permite llamadas de método de cada instrucción execute, independientemente de la tipo de instrucción. Uno puede agregar más métodos a la interfaz; en este ejemplo, se podría agregar "toString" que convertiría la instrucción en texto.

Idea 2: Functors 

Establezca una clase base o interfaz para las funciones que desea utilizar. Colóquelos en un contenedor e itere sobre el contenedor. La iteración puede ser condicional también:

struct Functor_Interface 
{ 
    virtual std::string get_name(void) const = 0; 
    virtual void   execute(void) = 0; 
    virtual void   execute_if_name(const std::string& name) 
    { if (name == get_name()) 
    { 
     execute(); 
    } 
    } 
}; 

typedef std::vector<Functor_Interface *> Functor_Container; 
//... 
Functor_Container the_functors; 
//... 
Functor_Container::iterator iter; 
for (iter = the_functors.begin(); 
    iter != the_functors.end(); 
    ++iter) 
{ 
    (*iter)->execute_if_name("loader"); // Execute the functor if it is a *loader*. 
    (*iter)->execute_if_name("math"); 
} 

En resumen, creo que por encima de su diseño para ver si hay un mejor proceso que no requiere nombres de función, sino que le permite ya sea la función de decidir ejecutar o genéricamente ejecuta ciegos métodos.

1

Para C++ directo, la respuesta anterior es buena. Sin embargo, algunos kits de herramientas (por ejemplo, Qt) pueden agregar introspección a C++. Este es quizás un cambio más pesado y no lo que desea para un proyecto existente, pero si está comenzando un proyecto que podría necesitar introspección, vale la pena buscar toolkits/wrappers que lo agreguen.

Cuestiones relacionadas