2011-11-25 14 views
5

Eventuali duplicati:
Is there a way to instantiate objects from a string holding their class name?Come posso istanziare un oggetto conoscendo solo il suo nome?

In C++, voglio avere il mio utente immettere il nome tipo di oggetto da creare in fase di esecuzione, e, a seconda della stringa ottengo da loro, il programma istanzia l'oggetto corretto (in breve, sto implementando un modello di metodo factory). Tuttavia, se il programma deve supportare un nuovo tipo di oggetto, la modifica del codice esistente non è consentita.

Quindi è possibile rimuovere tutto il if ... else if ... else if ... roba dal metodo, e avere ancora il mio programma che istanzia un oggetto corretto di un tipo specifico di prodotto (tra tanti, che sono noti solo al momento della compilazione)?

La mia ricerca in giro mi ha ottenuto questo link: Is there a way to instantiate objects from a string holding their class name? e sembra sia quello che voglio ma non riesco a capire il codice.

Qualsiasi aiuto sarebbe molto apprezzato.

+0

@CharlesB non è necessario il riflesso, è possibile utilizzare una fabbrica. –

+1

@LuchianGrigore: la fabbrica è un motivo di progettazione, la riflessione è una funzione del linguaggio. Se vuoi una factory che lavori senza if..else..else ... hai bisogno di un linguaggio che abbia riflessioni, o un'architettura di plugin binario, come nella risposta di Alessandro – CharlesB

risposta

5

questo funziona solo se tutte le classi richieste sono derivate da un po 'di classe base comune, e vi sarà generalmente limitata a utilizzare l'interfaccia di base (anche se è possibile lavorare intorno a ciò con qualche sforzo aggiuntivo). Ecco un approccio:

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

Ora è possibile aggiungere nuove classi derivate dal nuovo codice:

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

per creare una classe, è sufficiente chiamare Base * p = Base::create_from_string("Foo");.

+0

Le funzioni 'clone()' sono necessarie qui? Non sono sicuro se sia una buona idea spogliarli. – Daan

+0

@Daan: hai ragione, non sono necessari per la fabbrica di per sé, ma assumono il ruolo del costruttore di copie in situazioni in cui non conosci il tipo più derivato di un oggetto, quindi sono correlati a temi . –

+0

Quindi, se ho capito bene, ho bisogno che vengano lanciati da 'Base *' a 'Derived *'? – Daan

2

Si può fare ciò implementando qualcosa come un sistema di plugin. L'ho implementato in Linux con dlopen. Non è necessario modificare il programma, ma è necessario aggiungere solo nuove classi come librerie dinamiche che verranno caricate in fase di runtime.

Si può iniziare qui per ulteriori informazioni: C++ dlopen mini HOWTO

Problemi correlati