Array/Vector einer Template-Klasse, deren Template-Typ von einer Base Klasse erbt
-
Hallo zusammen,
Ich bin heute auf folgendes Problem gestoßen und weiß nicht wie ich dabei vorgehen sollte:Grundsätzlich will ich in einem Array/Vector verschiedene Instanzen einer Klasse "TMPL" (mit template Parameter T) speichern.
Die einsetzbaren Template-Klassen sollte dabei alle von Klasse "Base" erben (Im Beispiel: "A", "B")Beispiel:
#include <vector> struct Base { unsigned int ui = 10; }; struct A : public Base { const char* i = "text"; int i = 4; double d = 20.0; }; struct B : public Base { double d = 20.0; float f = 20.0; long double ld = 23.0L; const char* i = "adfasdfasdf"; int i = 4; }; template<typename T> class TMPL { public: T i; }; int main() { std::vector<TMPL<Base>> m_vec; m_vec.insert(TMPL<A>()); // HERE VS WON'T COMPILE }
Mein Problem ist, dass man Instanzen von unterschiedlichen Versionen der TMPL-Klasse nicht in einem einzelnen Vector speichern kann.
Hat wer eine Idee, wie ich vorgehen könnte?
Mfg
-
std::vector<TMPL<Base> *> m_vec;
und wo ist dein Problem?
-
@Swordfish sagte in Array/Vector einer Template-Klasse, deren Template-Typ von einer Base Klasse erbt:
und wo ist dein Problem?
Und was ist der Sinn dieser Frage, ausser dass sie dem Fragesteller implizit vermittelt, etwas falsches gefragt zu haben haben? Wenn die Lösung für ihn so selbstverständlich wäre, dann hätte er nicht gefragt.
std::vector<TMPL<Base> *> m_vec;
Ich vermute, dass hier die Idee sein soll, Pointer auf eine polymorphe Basisklasse in dem Array zu speichern. Das geht zwar, und ist auch oft eine Lösung, im vorliegenden Fall ist allerdings
TMPL<Base>
keine Basisklasse, sondern die Klasseninstanzen sind völlig unabhängig voneinander, weshalb diese vermeintliche Lösung ebenfalls nicht funktioniert.Ohne die
TMPL<T>
-Klasse ginge das durchaus, z.B. mit einemstd::vector<Base*>
oder besser so etwas wiestd::vector<std::unique_ptr<Base>>
, sofern es sich um eine polymorphe Klasse handelt (dazu benötigtBase
noch mindestens einen virtuellen Destruktor, also z.B.virtual ~Base() = default;
)Mit diesem
TMPL<T>
würde ich aber gerne zunächst fragen wollen, was du damit letztendlich erreichen willst @rnholzinger01 - bevor ich hier Dinge wiestd::any
,std::variant
vorschlage, oder empfehle, die Klassenhierarchie anders zu wählen. Davon hängt nämlich hab, welchen Lösungsansatz man hier am besten wählt oder ob der eingeschlagene Weg überhaupt Sinn macht.Finnegan
-
@rnholzinger01 sagte in Array/Vector einer Template-Klasse, deren Template-Typ von einer Base Klasse erbt:
Mein Problem ist, dass man Instanzen von unterschiedlichen Versionen der TMPL-Klasse nicht in einem einzelnen Vector speichern kann.
Hat wer eine Idee, wie ich vorgehen könnte?
MfgDa die unterschiedlichen Klassen unterschiedlich groß im Sinne von
sizeof(T)
sind, ist es generell schwierig so etwas durch den Compiler bereit zustellen. Deshalb gibt es keinen direkten Support durch Templates für Dein Vorgehen. Das einzige was direkt geht, ist eineine Smart Pointer Klasse z.B.std::shared_ptr<Base>
std::shared_ptr<Base>
oderstd::unique_ptr<Base>
im Container abzulegen. Man könnte natürlich einen Container bauen, der Platz für die größte vonBase
abgeleitete Klasse schafft, und es dann ermöglicht direkt im Container die Objekte zu speichern. Aber der Aufwand ist den Nutzen in der Regel nicht wert.
-
@john-0 sagte in Array/Vector einer Template-Klasse, deren Template-Typ von einer Base Klasse erbt:
Das einzige was direkt geht, ist ein
std::shared_ptr<Base>
im Container abzulegen.Nein, siehe @Finnegan s Antwort.
Ein vector mit unique_ptr entspricht auch eher einem "normalen" vector (dem gehört sein Inhalt auch und shared nichts).
-
@Jockelx sagte in Array/Vector einer Template-Klasse, deren Template-Typ von einer Base Klasse erbt:
Nein, siehe @Finnegan s Antwort.
Ja, erwischt schlecht formuliert. „Man muss dann eine der Smart Pointer Klassen von C++ nutzen.“, wäre mit Sicherheit die bessere Wortwahl gewesen.
Was das Thema
unique_ptr
betrifft, man kann keine Kopien erzeugen, was von der Logik an Brilianz für den Entwurf eindeutig nicht zu überbieten ist. Nur hat C++ nicht an Ausdruckskraft durch alle die notwendigen Sprachänderungen gewonnen, die dafür notwendig waren.
-
@john-0 sagte in Array/Vector einer Template-Klasse, deren Template-Typ von einer Base Klasse erbt:
@Jockelx sagte in Array/Vector einer Template-Klasse, deren Template-Typ von einer Base Klasse erbt:
Nein, siehe @Finnegan s Antwort.
Ja, erwischt schlecht formuliert. „Man muss dann eine der Smart Pointer Klassen von C++ nutzen.“, wäre mit Sicherheit die bessere Wortwahl gewesen.
Ne, darum geht´s nicht. Der Punkt ist, dass
TMPL<Base>
ein anderer Typ alsTMPL<A>
ist, auch wennA
vonBase
erbt.
-
@john-0 sagte in Array/Vector einer Template-Klasse, deren Template-Typ von einer Base Klasse erbt:
Was das Thema
unique_ptr
betrifft, man kann keine Kopien erzeugen, was von der Logik an Brilianz für den Entwurf eindeutig nicht zu überbieten ist. Nur hat C++ nicht an Ausdruckskraft durch alle die notwendigen Sprachänderungen gewonnen, die dafür notwendig waren.Naja, das Problem hast du aber in C#, Java oder sowas auch.
-
@john-0 sagte in Array/Vector einer Template-Klasse, deren Template-Typ von einer Base Klasse erbt:
Was das Thema
unique_ptr
betrifft, man kann keine Kopien erzeugen, was von der Logik an Brilianz für den Entwurf eindeutig nicht zu überbieten ist.Man kann durchaus Kopien erzeugen:
std::unique_ptr<int> p = std::make_unique<int>(5); int* zeiger_kopie = p.get(); std::unique_ptr<int> objekt_kopie = std::make_unique<int>(*p);
Was allerdings zurecht schwer gemacht wird, ist zwei besitzende Zeiger (
unique_ptr
) zu erzeugen, die sich um dasselbe Objekt zanken.Das wirkt sich dann natürlich auch auf Container aus, die solche
unique_ptr
halten. Einenstd::vector<std::unique_ptr<int>>
müsste man schon manuell in einenstd::vector<int*>
oder einen anderen Vektor des selben Typs kopieren. Das braucht man meiner Meinung nach aber nur recht selten, und wenn doch, dann halte ich die Wahrscheinlichkeit für recht hoch, dass dann auch ein Vektor mitshared_ptr
gerechtfertigt ist, bei dem das Kopieren kein Problem ist.
-
@rnholzinger01 sagte in Array/Vector einer Template-Klasse, deren Template-Typ von einer Base Klasse erbt:
Mein Problem ist, dass man Instanzen von unterschiedlichen Versionen der TMPL-Klasse nicht in einem einzelnen Vector speichern kann.
Naja du kannst immer einen
shared_ptr<void>
nehmen. Damit kannst du alles in den selbenvector
stopfen, ganz egal um welche Klasse es sich handelt. Oder du kannstTMPL
von einer non-template Basisklasse mit virtuellem Destruktor ableiten und dannunique_ptr<DieseNonTemplateBasisklasse>
in denvector
stecken.Oder, falls du nur Zugriff auf
Base
Funktionen brauchst, kannst du einenshared_ptr<Base>
nehmen. Das funktioniert auch wenn das Objekt tatsächlich einTMPL<A>
ist welches nur einA
(und damit einBase
) beinhaltet, aber nicht davon erbt. Dazu gibt es den aliasing-Konstruktor. So kannst du einenshared_ptr<Base>
bekommen der auf das inTMPL<A>
enthalteneA
Objekt zeigt, gleichzeitig aber das ganzeTMPL<A>
am Leben hält.Ansonsten müsste man wissen was du mit den
TMPL<T>
Instanzen in demvector
machen möchtest.
-
@Finnegan sagte in Array/Vector einer Template-Klasse, deren Template-Typ von einer Base Klasse erbt:
Man kann durchaus Kopien erzeugen:
Er meinte sicherlich, dass das hier mit den Basiszeigern aber nicht so einfach geht. Oder wie kopierst du da die Objekte (=rufst den richtigen Copy-ctor auf)?
Die Möglichkeit die ich kenne, ist halt eine "clone"-Funktion zu basteln (daher auch der Verweis auf C# & java).
-
@Jockelx sagte in Array/Vector einer Template-Klasse, deren Template-Typ von einer Base Klasse erbt:
Die Möglichkeit die ich kenne, ist halt eine "clone"-Funktion zu basteln (daher auch der Verweis auf C# & java).
Du bist so dermaßen eklig!
-
@Swordfish sagte in Array/Vector einer Template-Klasse, deren Template-Typ von einer Base Klasse erbt:
Du bist so dermaßen eklig!
Hör auf mit deinen Beleidigungen, das nervt. Schlag lieber eine Alternative vor. Ich verstehe dich nicht. Ein Teil deiner Beiträge ist sachbezogen und gut, der andere Teil irgendwie störend, merkwürdig und nutzlos.
-
@wob sagte in Array/Vector einer Template-Klasse, deren Template-Typ von einer Base Klasse erbt:
Schlag lieber eine Alternative vor.
Das war keine Beleidigung, sondern eine Feststellung. Beobachtbares Verhalten. Aber na schön:
#include <memory> #include <vector> #include <iostream> struct Base { virtual void talk() = 0; virtual ~Base() {}; }; struct A : Base { virtual void talk() override { std::cout << "A\n"; } virtual ~A() { std::cout << "A::d-tor()\n"; } }; struct B : Base { virtual void talk() override { std::cout << "B\n"; } virtual ~B() { std::cout << "B::d-tor()\n"; } }; struct C : Base { virtual void talk() override { std::cout << "C\n"; } virtual ~C() { std::cout << "C::d-tor()\n"; } }; int main() { std::vector<std::shared_ptr<Base>> foo; foo.push_back(std::make_shared<A>()); foo.push_back(std::make_shared<B>()); foo.push_back(std::make_shared<C>()); for (auto const &f : foo) f->talk(); }
Output:
A B C A::d-tor() B::d-tor() C::d-tor()
Aber ich weiß nicht, wieso ich hier das Kindermädchen spielen soll. @hustbaer hat schon alles gesagt.
ach so. kopieren. warum will ich das?
Base *bar{ foo[1].get() }; bar->talk();
*Wirklich* kopieren kann /* edit: */ wenn man den Typ nicht kennt /* edit */ in einer stark typisierten Sprache nur über verrenkungen gehen.