Generazione di un'istanza di classe derivata da una stringa con il suo nome.(cioè riflessione)

StackOverflow https://stackoverflow.com/questions/4231205

Domanda

Se ho una classe base:

class Base 
{
public:
virtual void Test()=0;
};

e, in un modulo caricato dinamicamente (.so/.dll), ho implementato una classe derivata da questa:

class SomethingFromBase : Base 
{
...
};

e l'utente, una volta caricata questa libreria, chiede di creare un'istanza di SomethingFromBase (diciamo che prendiamo il nome da cin.), e di cui non abbiamo conoscenza SomethingFromBase (vale a dire, non c'è modo di farlo if(inputstr == "SomethingFrombase") { ... } esiste un modo per creare un'istanza di SomethingFromBase?

Sono abbastanza certo che ciò sia impossibile in C++ (standard), ma spero sempre che SO mi sorprenda!

Se questo è possibile con l'aggiunta di qualche libreria, mi piacerebbe comunque saperlo.Grazie!

Modificare: Vedi la risposta di cdhowie.Guide per implementare questa tecnica:http://www.linuxjournal.com/article/3687?page=0,1http://www.abstraction.net/ViewArticle.aspx?articleID=67

È stato utile?

Soluzione

In genere si ottiene questo risultato richiedendo che le librerie dei plugin definiscano alcune variabili globali di un tipo struct che contenga puntatori a varie funzioni che è possibile chiamare.(Come installazione, smontaggio, ecc.) Durante la funzione di installazione, richiamerebbero nella tua applicazione una funzione di "registrazione" in cui potrebbero passare una stringa che rappresenta il nome della classe e un puntatore alla funzione di fabbrica che creerà un istanza quando eseguito.

Lo nascondi in qualche mappa e quando l'utente inserisce una stringa, guardi la mappa per vedere se è registrata una funzione di fabbrica.Se è così, basta chiamarlo.

Quindi questa non è una riflessione "vera", ma puoi modificarla manualmente in una certa misura.Vedi, ad esempio, Pidgin, che consente la specifica di plugin di protocollo che possono fornire molte voci nell'elenco dei protocolli.

MODIFICARE: Ecco una guida ingegnosa per implementare qualcosa di simile.Sono più una persona C, quindi non posso garantire che sia davvero fantastico o altro, ma a prima vista sembra buono.Ho fatto cose simili in C su Linux e l'approccio di base funziona piuttosto bene.

Altri suggerimenti

Chiedi a una mappa di memorizzare gli oggetti della classe, identificati dal nome della classe.Tutte le classi che devono essere create in questo modo, devono essere derivate da una classe di base denominata qualcosa come "creabile" il codice per aggiungere l'oggetto della classe deve essere dato con l'implementazione della classe.

//Creatable.h
#define IMPLEMENT_CREATABLE( ClassName ) \
  ObjectMap::Instance().Add( string(ClassName), new ClassName );

//ObjectMap.h. This is a singleton
class ObjectMap
{
  ...........
  map<string, Creatable *> myMap;
  ...........
public:
  void Add( const string &className, Creatable * );
  Creatable * Get( const string &className );
};

//My Class.h
class MyClass : public Creatable
{
  ................
};

//My Class.cpp
IMPLEMENT_CREATABLE(MyClass);


//Client.cpp
string className;
cin>>className;
Creatable *anObject = ObjectMap::Instance().Get( className );
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top