2011-01-16 7 views
2

ist es möglich, ein Exemplar des Objekts mit übergebenen Typ Name (String) in C++? Ich habe einige Basis abstrakte Klasse Base und ein paar Derivate. Beispielcode:Machen Sie Objekt mit seinem Namen

class Base 
{ 
    /* ... */ 
}; 

class Der1 : public Base 
{ 
    /* ... */ 
}; 

class Der2 : public Base 
{ 
    /* ... */ 
}; 

Und ich brauche Funktion wie:

Base *objectByType(const std::string &name); 

Anzahl der Derivate Klassen sind veränderbar und ich will nicht, etwas machen wie von name Schalten und durch die Hände neuen Objekttyp zurück. Ist es in C++ möglich das automatisch zu tun?

p.s. Nutzung sollte wie folgt aussieht:

dynamic_cast<Der1>(objectByType("Der1")); 

ich rein C++ Code (krossplattformischen) benötigen. Boost ist zulässig.

+0

Dies klingt eine OS-spezifische Frage. Über welches Betriebssystem reden wir? –

+0

@sad_man, bitte update. Ich brauche eine plattformübergreifende Version. – Ockonal

+0

Wie kann "die Anzahl der Derivate" änderbar sein? Sind Sie bereit, die Derivate aus einer externen Bibliothek aufzurufen, die nach Ihrer Anwendung kompiliert wird? –

Antwort

2

Es gibt einen netten Trick, mit dem Sie eine factory method ohne eine Sequenz von if...else if... schreiben können.

(beachten Sie, dass, AFAIK, es in der Tat nicht möglich ist, zu tun, was Sie in C wollen ++ wie dieser Code in der Kompilierung erzeugt wird. Eine „Factory Method“ Design Pattern für diesen Zweck existiert)

Sie

Erstens Definieren Sie eine global repository für Ihre abgeleiteten Klassen. Sie kann in der Form std::map<std::string, Base*> vorliegen, d. H. Sie bildet einen Namen der abgeleiteten Klasse zu an instance dieser Klasse.

Für jede abgeleitete Klasse definieren Sie eine default constructor, die ein Objekt dieser Klasse dem Repository unter dem Namen der Klasse hinzufügt.Sie können auch eine statische Instanz der Klasse definieren:

// file: der1.h 
#include "repository.h" 

class Der1: public Base { 
public: 
    Der1() { repository[std::string("Der1")] = this; } 
}; 

// file: der1.cpp 
static Der1 der1Initializer; 

Konstrukteurs von statischen Variablen, noch bevor main() ausgeführt werden, so dass, wenn Ihr main beginnt bereits das Repository mit Instanzen aller abgeleiteten Klassen initialisiert haben.

Ihre Factory-Methode (z. B. Base::getObject(const std::string&)) muss die Repository-Map nach dem Klassennamen durchsuchen. Anschließend wird die Methode clone() des gefundenen Objekts verwendet, um ein neues Objekt desselben Typs zu erhalten. Sie müssen natürlich clone für jede Unterklasse implementieren.

Der Vorteil dieses Ansatzes besteht darin, dass beim Hinzufügen einer neuen abgeleiteten Klasse die Zusätze nur auf die Datei (en) beschränkt sind, die die neue Klasse implementieren. Das Repository und der Fabrikcode werden nicht geändert. Sie müssen natürlich Ihr Programm neu kompilieren.

+2

Standard-Konstruktor ist eine schlechte Möglichkeit, dies zu tun. Erstellen Sie einfach eine gewöhnliche globale Variable, wie zB "int", die mit einem Aufruf der Factory-Setup-Funktion initialisiert wird. z.B. 'static int g_factoryDer1Registration = Der1Factory :: Register();' Oder erstellen Sie eine Instanz einer verschachtelten Helper-Klasse. Aber erstellen Sie keine Instanz des Typs, den die Fabrik erzeugt, um die Fabrik zu registrieren, die auf jede mögliche Weise gegen das Prinzip der einheitlichen Verantwortung verstößt. –

+0

@Ben Voigt: Danke, dass du darauf hingewiesen hast. In der Tat sieht eine dedizierte 'Der1Factory :: Register()' Methode besser aus. – davka

+0

Gute Idee, und ohne Schalter/if-Anweisungen. – Ockonal

0

Ja das ist möglich! Überprüfen Sie diese sehr lustige Klasse namens Activator Sie können alles durch Type und string erstellen und kann sogar eine Liste von Parametern geben, so wird die Methode den entsprechenden Konstruktor mit den besten Satz von Argumenten aufrufen.

+1

Ich glaube nicht, dass die Frage für .Net gestellt wird. –

+0

Ist es crossplatform und verfügbar für C++? Ich sehe es basiert auf .Net oder etw so. – Ockonal

+3

Falsche Sprache, falsches Framework (es sei denn, das OP hat nicht erwähnt, dass er C++/CLI anstelle von C++ verwendet, was unwahrscheinlich ist). –

0

Wenn nicht missverstanden, sollte das Schlüsselwort typeid ein Teil dessen sein, was Sie suchen.

+0

Nein. 'Typeid' bietet eine Zuordnung von Typen zu typbeschreibenden Objekten (einschließlich des Typnamens als Zeichenfolge), aber die inverse Zuordnung ist in C++ nicht verfügbar. – Philipp

2

Dies ist in C++ nicht möglich.

Eine Möglichkeit ist, eine Fabrik zu schreiben und den übergebenen Namen einzuschalten, aber ich sehe, dass Sie das nicht wollen. C++ bietet keine echte Unterstützung für die Laufzeit-Reflektion über dynamic_cast hinaus, sodass diese Art von Problem schwer zu lösen ist.

+1

können Sie eine Fabrik ohne 'Schalter' schreiben - sehen Sie meine Antwort unten. – davka

0

Es ist nicht möglich. Sie haben die Funktion objectByType selbst schreiben:

Base* objectByType(const std::string& name) { 
    if (name == "Der1") 
    return new Der1; 
    else if (name == "Der2") 
    return new Der2; 
    // other possible tests 
    throw std::invalid_argument("Unknown type name " + name); 
} 
0

C++ nicht reflection unterstützt.

Meiner Meinung nach ist dies der einzige Punkt, wo Java C++ schlägt.
(ope nicht zu viele Down-Stimmen für diese ...)

Sie könnten etwas mit einem benutzerdefinierten Präprozessor erreichen, ähnlich wie MOC für Qt.

Verwandte Themen