Vamos a implementar una pequeña aplicación en la que el usuario pueda elegir el método de la clase que va a ejecutarse, vamos a tener una clase en la que crearemos varios métodos «ejecutables» por el usuario.
En el ejemplo que presento, aunque sea un poco repetitivo, estoy suponiendo que C++ no tiene reflexion, esto, dicho de una forma rápida es que una clase tenga la facultad de conocer sus miembros, podremos llamarlos, pero no podremos decirle que nos dé una lista. Hay formas de hacerlo, creando macros, con trucos al compilar, etc; pero para este ejemplo, veo mucho más rápido y más claro implementar un mapa con los nombres de los métodos y sus direcciones.
Creamos una clase Invoker, que será capaz de ejecutar métodos por su nombre, los métodos, supondremos que son todos de la forma:
void metodo(int numero);
Aunque sería fácil cambiarlo.
Los archivos de este post se podrán descargar al final.
Empezamos invocando métodos de la misma clase invocadora, en el siguiente ejemplo tendremos el método void hola(int), y lo podremos llamar desde invoke(). Aunque antes, sí que es necesario que la clase añada al mapa availableMethods los métodos que se podrán llamar (como comentábamos antes, la propiedad de reflexión de C++).
invoker.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | /* @(#)invoker.h */ #ifndef _INVOKER_H #define _INVOKER_H 1 #include <string> #include <map> #define ADDMETHOD(class,name) this->availableMethods[#name] = &class::name; class Invoker { public: typedef void (Invoker::*Method)(int); Invoker(); ~Invoker(); void invoke(std::string method, int argument); void hola(int arg); void listMethods(); private: std::map<std::string, Method> availableMethods; }; #endif /* _INVOKER_H */ |
invoker.cpp
Aquí se hace uso de los punteros a miembro (encerrados en el mapa) para poder llamar al método cuyo nombre corresponde con la cadena recibida.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | /** ************************************************************* * @file invoker.cpp *************************************************************/ #include "invoker.h" #include <iostream> #include <stdexcept> #include <typeinfo> using namespace std; Invoker::Invoker() { cout << "Inicializo invoker" << endl; ADDMETHOD(Invoker, hola); } Invoker::~Invoker() { } void Invoker::invoke(std::string method, int argument) { Method m = availableMethods[method]; if (m == NULL) throw new runtime_error("No se encuentra el método"); (this->*m)(argument); } void Invoker::listMethods() { for (map<string, Method>::iterator i=availableMethods.begin(); i!=availableMethods.end(); ++i) { cout <<i->first<<endl; } } void Invoker::hola(int arg) { cout << "Hola, me has dado el numero "<<arg<<endl; } |
main.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | /** ************************************************************* * @file main.cpp *************************************************************/ #include <iostream> #include "invoker.h" #include <stdexcept> using namespace std; int main(int argc, char *argv[]) { Invoker invoker; cout << "Inicio del programa" << endl; cout << "Métodos disponibles: "<<endl; invoker.listMethods(); cout << "Invoco métodos:" << endl; try { invoker.invoke("hola", 12); invoker.invoke("adios", 12); } catch (runtime_error *e) { cout << "Ha habido un problema: "<<e->what()<<endl; } } |
En estos tres archivos, tendremos la clase Invoker, desde la que se llamará a un método de la misma (con el prototipo especificado). Cada uno de los métodos debe estar en el mapa (extendiendo este mapa, podremos gestionar permisos de los métodos a ciertos usuarios, por ejemplo. Para añadir elementos al mapa, y hacerlo de forma un poco más fácil, se ha creado la macro ADDMETHOD(Invoker, metodo); por ahora, todos los métodos estarán en Invoker, por lo que el primer argumento se queda igual. En ese punto se hará algo como:
this->availableMethods[«nombredelmetodo»] = &Invoker::nombredelmetodo;
En este punto podemos incluir un método para comprobar el nombre, devolver una excepción cuando el método existe, añadir permisos, etc.
Pero la gracia de esto reside en que podamos tener una clase base Invoker y varias clases derivadas de ésta, en donde cada una tenga unos métodos propios. En el siguiente ejemplo, veremos cómo hemos creado una clase Controller, derivada de Invoker, en la que llamaremos a métodos propios que hemos añadido:
invoker.h
En esta clase, lo único que he añadido es el casting en la macro ADDMETHOD, ya que no estaremos tratando siempre de la misma clase, el compilador tratará Invoker::metodo() y Controller::metodo() de forma diferente, tenemos que decirle que siempre piense que son Invoker::metodo(), para no crear un tipo para cada una de las nuevas clases que creemos. Por otro lado, el typedef ahora es protected.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | /* @(#)invoker.h */ #ifndef _INVOKER_H #define _INVOKER_H 1 #include <string> #include <map> #define ADDMETHOD(class,name) this->availableMethods[#name] = static_cast<Method> (&class::name); class Invoker { public: Invoker(); ~Invoker(); void invoke(std::string method, int argument); void listMethods(); protected: typedef void (Invoker::*Method)(int); std::map<std::string, Method> availableMethods; }; #endif /* _INVOKER_H */ |
invoker.cpp
Se ha eliminado el método hello
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | /** ************************************************************* * @file invoker.cpp *************************************************************/ #include "invoker.h" #include <iostream> #include <stdexcept> #include <typeinfo> using namespace std; Invoker::Invoker() { cout << "Inicializo invoker" << endl; } Invoker::~Invoker() { } void Invoker::invoke(std::string method, int argument) { Method m = availableMethods[method]; if (m == NULL) throw new runtime_error("No se encuentra el método ""+method+"""); (this->*m)(argument); } void Invoker::listMethods() { for (map<string, Method>::iterator i=availableMethods.begin(); i!=availableMethods.end(); ++i) { cout <<i->first<<endl; } } |
controller.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* @(#)controller.h */ #ifndef _CONTROLLER_H #define _CONTROLLER_H 1 #include "invoker.h" class Controller : public Invoker { public: Controller(); ~Controller(); void hello(int number); void goodbye(int number); void downloadData(int number); }; #endif /* _CONTROLLER_H */ |
invoker.cpp
¡¡Aquí ya tenemos total libertad!!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | /** ************************************************************* * @file controller.cpp *************************************************************/ #include "controller.h" #include <iostream> using namespace std; Controller::Controller() { ADDMETHOD(Controller, hello); ADDMETHOD(Controller, goodbye); ADDMETHOD(Controller, downloadData); } Controller::~Controller() { } void Controller::hello(int number) { cout << "Hello "<<number<<endl; } void Controller::goodbye(int number) { cout << "Goodbye "<<number<<endl; } void Controller::downloadData(int number) { cout << "Now I will download everything I need" << endl; } |
main.cpp
Un pequeño programa principal en donde pedimos al usuario que escriba el nombre del método que queremos cargar.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | /** ************************************************************* * @file main.cpp *************************************************************/ #include <iostream> #include "controller.h" #include <stdexcept> #include <string> using namespace std; int main(int argc, char *argv[]) { Controller controller; string ask; cout << "Inicio del programa" << endl; cout << "Métodos disponibles: "<<endl; controller.listMethods(); cout << "Invoco métodos:" << endl; do { cin >> ask; try { controller.invoke(ask, 12); } catch (runtime_error *e) { cout << "Ha habido un problema: "<<e->what()<<endl; } } while (ask!="goodbye"); } |
Para descargar los archivos: invoca_metodosr.tar (1.6Kb)
Foto: Ju-x (Flickr) CC-by
Your blog provided us with valuable information. I am looking forward to read more blog posts from here keep it up!!Santa Claus Red Vest
This is excellent article, thank you for the share! This is what I am looking for, hope in future you will continue sharing such an superb work.
Top Gun Bomber Jacket
So luck to come across your excellent blog. Your blog brings me a great deal of fun.. Good luck with the site. gate valve manufacturer
It was a decent post to be sure. I completely delighted in understanding it in my lunch time. Will definitely come and visit this blog all the more frequently. Much obliged for sharing. laser target shooting system
I like this post,And I figure that they having a great time to peruse this post,they might take a decent site to make an information,thanks for sharing it to me. shilajit benefits for male
Great job for publishing such a beneficial web site. Your web log isn’t only useful but it is additionally really creative too. There tend to be not many people who can certainly write not so simple posts that artistically. Continue the nice writing NBA即時比分
I was surfing net and fortunately came across this site and found very interesting stuff here. Its really fun to read. I enjoyed a lot. Thanks for sharing this wonderful information. electrician near me
I want you to thank for your time of this wonderful read!!! I definitely enjoy every little bit of it and I have you bookmarked to check out new stuff of your blog a must read blog funny onesies for baby boy
I want you to thank for your time of this wonderful read!!! I definately enjoy every little bit of it and I have you bookmarked to check out new stuff of your blog a must read blog! Company in Estonia
Hmm!! This blog is really cool, I’m so lucky that I have reached here and got this awesome information. you may now band the bride panties
definately enjoy every little bit of it and I have you bookmarked to check out new stuff of your blog a must read blog! nausea sneezing
Great job for publishing such a beneficial web site. Your web log isn’t only useful but it is additionally really creative too. There tend to be not many people who can certainly write not so simple posts that artistically. Continue the nice writing Eugenio Pallisco Michigan
Yes, great US Military force. Also, in his post you have given a chance to listen about US Military. I really appreciate your work. Thanks for sharing it. Sherry Guidry Device Technology
Great article with excellent idea!Thank you for such a valuable article. I really appreciate for this great information.. Emerald of Katong Jalan Tembusu
Hmm!! This blog is really cool, I’m so lucky that I have reached here and got this awesome information. how to choose a solar installer to finance b2b
You have a great sense of writing I must say. Your post has those facts which are not accessible from anywhere else. It’s my humble request to u please keep writing such remarkable articles top kubota models
I’m constantly searching on the internet for posts that will help me. Too much is clearly to learn about this. I believe you created good quality items in Functions also. Keep working, congrats! bachelorette underwear
This is exceptionally instructive substance and composed well for a change. It’s pleasant to see that a few individuals still see how to compose a quality post! 네네티비
You have a great sense of writing I must say. Your post has those facts which are not accessible from anywhere else. It’s my humble request to u please keep writing such remarkable articles fire fighter funny panty
Awesome things you’ve generally imparted to us. Simply continue written work this sort of posts.The time which was squandered in going for educational cost now it can be utilized for studies.Thanks Personal trainer Winter Springs FL
If you’re looking for personal security services in New York, there are several reputable companies and agencies that provide such services. Here are a few steps you can take to find the right one for your needs: By following these steps, you can find a reputable personal security service in New York that meets your needs and provides you with peace of mind.Personal Security Guard Services New York