Publi

Invocando métodos por su nombre (en string) con C++

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

También podría interesarte....

There are 21 comments left Ir a comentario

  1. Mike Rooney /
    Usando Google Chrome Google Chrome 119.0.0.0 en Windows Windows NT

    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

  2. Andrew Mark /
    Usando Google Chrome Google Chrome 119.0.0.0 en Windows Windows NT

    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

  3. Jones Elizabeth /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    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

  4. Jones elizebeth /
    Usando Google Chrome Google Chrome 121.0.0.0 en Windows Windows NT

    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

  5. Jones elizebeth /
    Usando Google Chrome Google Chrome 121.0.0.0 en Windows Windows NT

    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

  6. Jones elizebeth /
    Usando Google Chrome Google Chrome 121.0.0.0 en Windows Windows NT

    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即時比分

  7. Jones elizebeth /
    Usando Google Chrome Google Chrome 122.0.0.0 en Windows Windows NT

    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

  8. Jones elizebeth /
    Usando Google Chrome Google Chrome 122.0.0.0 en Windows Windows NT

    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

  9. Jones elizebeth /
    Usando Google Chrome Google Chrome 122.0.0.0 en Windows Windows NT

    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

  10. Jones elizebeth /
    Usando Google Chrome Google Chrome 122.0.0.0 en Windows Windows NT

    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

  11. Jones elizebeth /
    Usando Google Chrome Google Chrome 122.0.0.0 en Windows Windows NT

    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

  12. Jones elizebeth /
    Usando Google Chrome Google Chrome 122.0.0.0 en Windows Windows NT

    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

  13. Jones elizebeth /
    Usando Google Chrome Google Chrome 122.0.0.0 en Windows Windows NT

    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

  14. Jones elizebeth /
    Usando Google Chrome Google Chrome 122.0.0.0 en Windows Windows NT

    Great article with excellent idea!Thank you for such a valuable article. I really appreciate for this great information.. Emerald of Katong Jalan Tembusu

  15. Jones elizebeth /
    Usando Google Chrome Google Chrome 122.0.0.0 en Windows Windows NT

    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

  16. Mica /
    Usando Google Chrome Google Chrome 123.0.0.0 en Windows Windows NT

    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

  17. Jones elizebeth /
    Usando Google Chrome Google Chrome 123.0.0.0 en Windows Windows NT

    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

  18. Jones Elizabeth /
    Usando Google Chrome Google Chrome 123.0.0.0 en Windows Windows NT

    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! 네네티비

  19. Jones Elizabeth /
    Usando Google Chrome Google Chrome 123.0.0.0 en Windows Windows NT

    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

  20. Jones Elizabeth /
    Usando Google Chrome Google Chrome 124.0.0.0 en Windows Windows NT

    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

  21. Giovanni /
    Usando Google Chrome Google Chrome 124.0.0.0 en Windows Windows NT

    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

Leave a Reply