2011-11-25 17 views
5

Duplicar posible:
Is there a way to instantiate objects from a string holding their class name?¿Cómo puedo instanciar un objeto sabiendo solo su nombre?

En C++, yo quiero tener mi usuario introduzca el nombre del tipo de objeto que se ha creado en tiempo de ejecución, y, dependiendo de la cadena de recibo de ellos, el programa instanciará el objeto correcto (en resumen, estoy implementando el patrón de método de fábrica). Sin embargo, si el programa tiene que admitir un nuevo tipo de objeto, entonces no se permite modificar el código existente.

Entonces, ¿es posible eliminar todo el if ... else if ... else if ... cosas del método, y todavía tener mi programa instanciar un objeto correcto de un tipo de producto específico (de muchos, que se conocen solo en tiempo de compilación)?

Mi búsqueda alrededor me consiguió este enlace: Is there a way to instantiate objects from a string holding their class name? y parece que es lo que quiero, pero no puedo entender el código en absoluto.

Cualquier ayuda sería muy apreciada.

+0

@CharlesB no necesita reflexión, puede utilizar una fábrica. –

+1

@LuchianGrigore: fábrica es un patrón de diseño, la reflexión es una función de idioma. Si quieres una fábrica que funcione sin if ... else ... else ... necesitas un lenguaje que tenga reflejo, o una arquitectura de complemento binario, como en la respuesta de Alessandro – CharlesB

Respuesta

5

esto sólo funcionará si todas las clases requeridas se derivan de alguna clase base común, y que no rebasará a través de la interfaz de base (aunque se puede trabajar alrededor de eso con un poco de esfuerzo adicional). Aquí es uno de los enfoques:

// Immutable core code: 

#include <map> 
#include <string> 

class Base 
{ 
    typedef Base * (*crfnptr)(const std::string &); 
    typedef std::map<std::string, crfnptr> CreatorMap; 

    static CreatorMap creators; 

public: 
    virtual ~Base() { } 
    Base * clone() const { return new Base(*this); } 

    static Base * create_from_string(std::string name) 
    { 
    CreatorMap::const_iterator it = creators.find(name); 
    return it == creators.end() ? NULL : it->first(); 
    } 

    static void register(std::string name, crfnptr f) 
    { 
    creators[name] = f; 
    } 
}; 

Ahora puede añadir nuevas clases derivadas de su nuevo código:

// your code: 

#include "immutable_core.hpp" 

class Foo : public Base 
{ 
public: 
    Foo * clone() const { return new Foo(*this); } 
    static Foo * create() { return new Foo; } 
}; 

Base::register("Foo", &Foo::create); 

para crear una clase, sólo tiene que llamar Base * p = Base::create_from_string("Foo");.

+0

¿Se necesitan las funciones 'clone()' aquí? No estoy seguro de si es una buena idea eliminarlos. – Daan

+0

@Daan: tiene razón, no son necesarios para la fábrica per se, pero toman el rol del constructor de copias en situaciones en las que no conoce el tipo más derivado de un objeto, por lo que están relacionados temáticamente . –

+0

Entonces, si entiendo correctamente, los necesito para emitir desde 'Base *' a 'Derived *'? – Daan

2

Puede hacer eso implementando algo así como un sistema de complemento. Lo he implementado en Linux con dlopen. No es necesario modificar el programa, pero solo necesita agregar nuevas clases como bibliotecas dinámicas que se cargarán en el tiempo de ejecución.

Puede comenzar aquí para obtener más información: C++ dlopen mini HOWTO

Cuestiones relacionadas