Ich möchte eine Reihe von Objekten von Klassen verwalten, die von einer gemeinsam genutzten Schnittstellenklasse in einem gemeinsamen Container abgeleitet sind.
Um das Problem zu veranschaulichen, lasst uns sagen, ich baue ein Spiel, das verschiedene Schauspieler enthalten wird. Lassen Sie uns die Schnittstelle IActor
nennen und daraus Enemy
und Civilian
ableiten.
Nun, die Idee ist, dass meine Hauptschleife dafür in der Lage ist:
%Vor%und
%Vor%... oder etwas in dieser Richtung. Dieses Beispiel wird offensichtlich nicht funktionieren, aber das ist ziemlich genau der Grund, warum ich hier frage.
Ich würde gerne wissen: Was wäre die beste, sicherste und höchste Art, diese Objekte in einem gemeinsamen heterogenen Container zu verwalten? Ich kenne eine Vielzahl von Ansätzen (Boost :: Any, void *, Handler-Klasse mit boost :: shared_ptr, Boost.Pointer Container, dynamic_cast), aber ich kann mich nicht entscheiden, welcher Weg so gehen würde.
Ich möchte auch betonen, dass ich so weit wie möglich von der manuellen Speicherverwaltung oder verschachtelten Zeigern wegbleiben möchte.
Hilfe sehr geschätzt:).
Wie Sie vermutet haben, müssen Sie die Objekte als Zeiger speichern.
Ich bevorzuge die Verwendung der Boost-Pointer-Container (anstelle eines normalen Containers von Smartpointern).
Der Grund dafür ist, dass der ptr-Container "boost" auf die Objekte zugreift, als wären sie Objekte (die Referenzen zurückgeben) und nicht als Zeiger. Dies erleichtert die Verwendung von Standardfunktionen und -algorithmen auf den Containern.
Der Nachteil von intelligenten Zeigern ist, dass Sie das Eigentumsrecht teilen.
Das ist nicht das, was du wirklich willst. Sie möchten, dass sich das Eigentumsrecht an einem einzigen Ort befindet (in diesem Fall dem Container).
und
%Vor%Um das Problem zu lösen, das Sie erwähnt haben, obwohl Sie in die richtige Richtung gehen, aber Sie tun es in die falsche Richtung. Das müssen Sie tun
Enemy
und Civilian
überschrieben würden. std::vector<IActor>
genommen, was keine gute Wahl ist
IActor
-Teil von Enemy
oder Civilian
anstelle des gesamten Objekts gespeichert wird. virtual functions
), was nur passieren kann, wenn Sie Zeiger verwenden. Beide oben genannten Gründe weisen auf die Tatsache hin, dass Sie einen Container verwenden müssen, der Zeiger enthalten kann, etwa wie std::vector<IActor*>
. Aber eine bessere Wahl wäre es, container of smart pointers
zu verwenden, was Sie vor Problemen beim Speichermanagement bewahrt. Sie können einen der Smart Pointer je nach Bedarf verwenden (aber nicht auto_ptr
)
So würde Ihr Code aussehen
%Vor%und
%Vor%Das ist Ihrem ursprünglichen Code ziemlich ähnlich, mit Ausnahme von Smart Pointer part
Wenn der Container ausschließlich die Elemente enthalten soll, verwenden Sie einen Boost-Pointer-Container: Sie sind für diesen Job konzipiert. Ansonsten benutze einen Container von shared_ptr<IActor>
(und benutze sie natürlich auch richtig, was bedeutet, dass jeder, der den Besitz teilen muss, shared_ptr
benutzt).
Stellen Sie in beiden Fällen sicher, dass der Destruktor von IActor
virtuell ist.
void*
erfordert manuelle Speicherverwaltung, das ist also nicht möglich. Boost.Any ist Overkill, wenn die Typen durch Vererbung verwandt sind - Standardpolymorphismus erledigt den Job.
Ob Sie dynamic_cast
benötigen oder nicht, ist ein orthogonales Problem - wenn die Benutzer des Containers nur die IActor-Schnittstelle benötigen und Sie entweder (a) alle Funktionen der Schnittstelle virtuell machen oder (b) die Nicht-virtuelle Schnittstelle Idiom, dann brauchen Sie nicht dynamic_cast. Wenn die Benutzer des Containers wissen, dass einige der IActor-Objekte "wirklich" Zivilisten sind und Dinge nutzen wollen, die sich auf der Civilian-Oberfläche befinden, aber nicht auf IActor, dann brauchen Sie Umwandlungen (oder ein Redesign).
Tags und Links c++ interface containers heterogeneous