2010-11-21 11 views
2

Ich habe viel zu lange in Java programmiert und bin wieder zu C++ zurückgekehrt. Ich möchte Code schreiben, der eine Klasse (entweder eine type_info oder ihr Name in einer Zeichenfolge) eine Instanz dieser Klasse erstellen kann. Der Einfachheit halber nehmen wir an, dass es nur den Standardkonstruktor aufrufen muss. Ist das in C++ überhaupt möglich und wenn nicht, kommt es in einer zukünftigen TR?Möglich, Objekt in C++ aufgrund seines Typs instanziieren?

Ich habe einen Weg gefunden, dies zu tun, aber ich hoffe, dass es etwas "dynamischeres" gibt. Für die Klassen, die ich instanziieren möchte (dies ist ein Problem an sich, da ich diese Entscheidung bis zur Konfiguration belassen möchte), habe ich eine Singleton-Factory mit einer statisch erstellten Instanz erstellt, die sich bei einer anderen Klasse registriert. z.B. Für die Klasse Foo gibt es auch eine FooFactory mit einer statischen FooFactory-Instanz, so dass beim Programmstart der FooFactory-Konstruktor aufgerufen wird, der sich bei einer anderen Klasse registriert. Wenn ich dann zur Laufzeit ein Foo erstellen möchte, finde ich die FooFactory und rufe sie auf, um die Foo-Instanz zu erstellen. Gibt es etwas Besseres in C++? Ich schätze, ich wurde gerade durch reiches Nachdenken in Java/C# verwöhnt.

Für den Kontext versuche ich, einige der IOC-Container-Konzepte, die ich in der Java-Welt so gewohnt bin, auf C++ anzuwenden, und hoffe, dass ich es so dynamisch wie möglich machen kann, ohne eine Factory hinzufügen zu müssen Klasse für jede andere Klasse in meiner Anwendung.

+0

Als eine Folge, ist es möglich, einen "Typ" in C++ zu übergeben? dh. Übergeben Sie kein Foo-Objekt, sondern die Foo-Klasse als Parameter für eine Funktion? Das Java-Äquivalent, an das ich denke, ist eine Methode, die einen Class-Parameter akzeptiert, und Sie können Foo.class übergeben – Greencpp

Antwort

0

Sie können immer Vorlagen verwenden, obwohl ich nicht sicher bin, dass dies, was Sie suchen:

template <typename T> 
T 
instantiate() 
{ 
    return T(); 
} 

Oder auf eine Klasse:

template <typename T> 
class MyClass 
{ 
    ... 
}; 
+0

Dank Joe. Ja, das Verwenden von Vorlagen könnte eine Möglichkeit sein, die Codezeilen zu trimmen, die für die Implementierung der Factory erforderlich sind. Ich hoffe jedoch, einen Weg zu finden, um zu vermeiden, dass eine Factory für jede Klasse dynamisch erstellt wird. Ich vermute, ich werde es nicht tun. – Greencpp

-1

Nein, es gibt keine Möglichkeit, vom Typnamen zum eigentlichen Typ wechseln; reiche Reflexion ist ziemlich cool, aber es gibt fast immer einen besseren Weg.

+1

Ja, ich vermute, dass der Versuch, die Java-Methode, IOC auf C++ auszuführen, groß ist, mein erster Fehler ist. Dennoch ist es sehr mächtig, die Klassen in der Config a la Spring dynamisch zu verdrahten. Mein Factory-Ansatz erfüllt diesen Wunsch, nur nicht so sauber, wie ich es möchte. – Greencpp

+1

BTW, wer gab die -1 hier, und warum ... Ich bin daran interessiert, warum Sie mit Jonathan nicht übereinstimmen. – Greencpp

+0

lol :) Jeder zu seinen eigenen. –

-1

nichts wie "var" oder "dynamisch" in C++ das letzte Mal, das ich überprüft habe (obwohl das vor einem WHILE war). Sie können einen (void *) Zeiger verwenden und dann versuchen, entsprechend zu casten. Auch, wenn Speicher mich richtig bedient, hat C++ RTTI, die keine Reflektion ist, aber helfen kann, Typen zur Laufzeit zu identifizieren.

+1

C++ 0x 'Auto' ist ziemlich genau das, was C# '' var' ist. Und beide haben absolut nichts mit dynamischem Tippen zu tun. – fredoverflow

0

Willkommen in C++ :)

Sie sind richtig, dass Sie eine Factory benötigen diese Objekte zu erstellen, jedoch können Sie nicht ein Factory pro Datei benötigen.

Der typische Weg zu gehen wird alle instanciable Klassen mit herleiten von einer gemeinsamen Basisklasse, dass wir Base nennen, so dass Sie eine einzelne Factory benötigen, die eine std::unique_ptr<Base> Ihnen jedes Mal dienen.

Es gibt 2 Möglichkeiten zur Umsetzung der Factory:

  • Sie können das Prototype Muster, und eine Instanz der Klasse registrieren zu erstellen, auf dem eine clone Funktion aufgerufen wird.
  • Sie können einen Zeiger auf Funktion oder einen Funktor (oder std::function<Base*()> in C++ 0x)

Natürlich registrieren die Schwierigkeit ist, dynamisch die Einträge zu registrieren. Dies geschieht typischerweise beim Start während der statischen Initialisierung.

// OO-way 
class Derived: public Base 
{ 
public: 
    virtual Derived* clone() const { return new Derived(*this); } 
private: 
}; 

// start-up... 
namespace { Base* derived = GetFactory().register("Derived", new Derived); } 

// ...or in main 
int main(int argc, char* argv[]) 
{ 
    GetFactory().register("Derived", new Derived(argv[1])); 
} 

// Pointer to function 
class Derived: public Base {}; 

// C++03 
namespace { 
    Base* makeDerived() { return new Derived; } 
    Base* derived = GetFactory().register("Derived", makeDerived); 
} 

// C++0x 
namespace { 
    Base* derived = GetFactory().register("Derived", []() { return new Derived; }); 
} 

Der Hauptvorteil der Start-up Art und Weise ist, dass Sie auf Ihre Derived Klasse in einer eigenen Datei definieren können, stecken die Registrierung gibt, und keine andere Datei, die von Änderungen betroffen ist. Dies ist ideal für die Handhabung von Abhängigkeiten.

Wenn der Prototyp, den Sie erstellen möchten, einige externe Informationen/Parameter benötigt, müssen Sie eine Initialisierungsmethode verwenden. Die einfachste Methode ist, Ihre Instanz in main (oder gleichwertig) zu registrieren haben die notwendigen Parameter.

Schnell Anmerkung: die Zeiger auf Funktionsmethode ist die wirtschaftlichste (im Speicher) und die schnellste (in der Ausführung), aber die Syntax ist seltsam ...

Im Hinblick auf den Folgefragen.

Ja, es ist möglich, eine Art auf eine Funktion zu übergeben, wenn auch vielleicht nicht direkt:

  • , wenn die in Rede stehenden Art zum Zeitpunkt der Kompilierung bekannt ist, können Sie die Vorlagen verwenden, wenn Sie einige brauchen Zeit kennen zu lernen mit der Syntax
  • wenn nicht, dann müssen Sie eine Art von ID passieren und verwenden Sie die Fabrik Ansatz

wenn Sie so etwas wie object.class passieren müssen dann scheint es mir, dass Sie nähern sich dem Doppelversand-Anwendungsfall und es würde sich lohnen, das Muster Visitor zu betrachten.

Verwandte Themen