Basteln einer eigenen Template-Containerklasse
-
servus,
hab mir gerade mal eine eigene Templateklasse geschrieben, die in einem späteren programm als basisklasse eines buffers verwendet wird. erstmal das problem mit der basisklasse selbst: ich habe die klassendefinition in ein headerfile verpackt und den rest in ein sourcefile. allerdings kann der compiler die methoden dann nicht mehr der templateklasse zuordnen. was muss ich dazuschreiben, damit er merkt, dass es sich um das gleiche template wie im header handelt?
template<class T>// so in etwa ?? aber dann würde es sich doch um ein neues template handeln oder? myContainerBase::myContainerBase<T>() { //... };jetzt zur abgeleiten Klasse: in der Basisklasse existiert folgende membervariable
private: static const size_t defaultsize = 1<<10;sie soll in der abgeleiteten klasse verschwinden, da sie dort ersetzt wird duch:
private: static const size_t maxsize = 1<<8;bin mir da nicht sicher ob die static-member auch in abgeleiteten klassen erhalten bleiben, wenn ja, wie kann ich das verhindern?
das letzte problem ist folgendes: in der abgeleiteten klasse wird bis auf die größe und das wegfallen des templatearguments nicht viel verändert:
class myContainerDerived : public myContainerBase<char>das dem buffer zugrundeliegende array bleibt also als member bestehn, jetzt eben vom typ char. alle virtual methoden bleiben der abgeleiteten klasse erhalten, klar, aber wie kann ich den operator= und den copy-ctor quasi 'virtual' deklarieren, damit ich ihn nicht doppelt schreiben muss. er macht ja schließlich genau dasselbe.
Vielen lieben dank im Voraus!
-
Zum ersten: Ja, bei der Definition der Methoden mußt du die Template-Parameter mit angeben:
template<typename T> class container { public: container(); ... }; template<typename T> container<T>::container() { ... }(der Compiler kann das schon einander zuordnen)
Btw solltest du die Methoden der Template-Klasse NICHT in eine eigene CPP auslagern, sonst bekommst du Probleme mit deinem Linker.
Zum zweiten: Abgeleitete Klassen können die Basis nur erweitern, das heißt es ist nicht möglich, die Member der Basisklasse verschwinden zu lassen. Bei nicht-statischen Membern könntest du eventuell den Inhalt überschreiben, wenn du drankommen könntest (Stichwort: protected).
Zum dritten: op= und den Copy-Ctor kannst du nicht virtuell definieren, brauchst du im Normalfall auch gar nicht. Wenn deine abgeleitete Klasse keine eigenen Daten kopieren muß, kannst du beide einfach weglassen und die vorgefertigten Versionen machen das, was nötig ist (Basisklasse und alle neu hinzugekommenen Member kopieren).
-
@ CStoll: Vielen Dank erstmal für die Antwort! aber nochmal zum ersten: habe da mal was gelesen von
template<> myContainer::myContainer()oder so ähnlich. wird anscheinend nicht von allen compilern unterstützt, da es erst neu in den Standard aufgenommen wurde, aber es ist jedenfalls Ansi-C++. kann es sein, dass sowas den gleichen zweck erfüllt?
und das mit dem auslagern der templatemethoden in eigene cpp files war mir nicht bekannt aber dafür gibts dann wohl die PCHs.zum zweiten: das ist nicht ganz so tragisch, wenns nicht klappt. und wenns sein muss kann ich sie tatsächlich noch als nicht-statisch deklarieren und überschreiben.
drittens: genau das ist das problem: es werden dynamische arrays verwendet. jetzt müsste ich den copy-ctor und den operator= eben nochmal schreiben (fast der gleich quelltext) und das würde sich schon fast mit der one-def-rule überschneiden. warscheinlich wärs dann sinnvoller eine virtual methode in der basisklasse bereitzustellen, die sowas erledigt, oder jeweils die ctoren der basisklasse aufzurufen.
-
Du kannst doch den Zuweisungsoperator über den CopyCtor definieren, so dass du da erstmal nur einmal kopieren mußt. Beim CopyCtor kannst du doch den der Basisklasse in der Initialisierungsliste ausführen.
-
slaughter schrieb:
@ CStoll: Vielen Dank erstmal für die Antwort! aber nochmal zum ersten: habe da mal was gelesen von
template<> myContainer::myContainer()oder so ähnlich. wird anscheinend nicht von allen compilern unterstützt, da es erst neu in den Standard aufgenommen wurde, aber es ist jedenfalls Ansi-C++. kann es sein, dass sowas den gleichen zweck erfüllt?
Nein, das ist eine Template-Spezialisierung (und da müsstest du noch angeben, für welchen Typ du das spezialisieren willst).
und das mit dem auslagern der templatemethoden in eigene cpp files war mir nicht bekannt aber dafür gibts dann wohl die PCHs.
Inwieweit dir vorcompilierte Header bei Templates weiterhelfen, bin ich nichtmal so sicher.
(im ANSI-Standard gibt es für so eine Trennung zwar das Schlüsselwort 'export' - aber das wird von kaum einem Compiler wirklich unterstützt).
drittens: genau das ist das problem: es werden dynamische arrays verwendet. jetzt müsste ich den copy-ctor und den operator= eben nochmal schreiben (fast der gleich quelltext) und das würde sich schon fast mit der one-def-rule überschneiden. warscheinlich wärs dann sinnvoller eine virtual methode in der basisklasse bereitzustellen, die sowas erledigt, oder jeweils die ctoren der basisklasse aufzurufen.
Solange die abgeleitete Klasse keine eigenen dynamischen Elemente anlegt und verwaltet, stört das überhaupt nichts. Die default-generierten Methoden rufen jeweils die entsprechenden Funktionen der Basisklasse und der eigenen Member auf - und die Basismethoden sind dann dafür zuständig, die dynamischen Arrays zu verwalten.
-
CStoll schrieb:
drittens: genau das ist das problem: es werden dynamische arrays verwendet. jetzt müsste ich den copy-ctor und den operator= eben nochmal schreiben (fast der gleich quelltext) und das würde sich schon fast mit der one-def-rule überschneiden. warscheinlich wärs dann sinnvoller eine virtual methode in der basisklasse bereitzustellen, die sowas erledigt, oder jeweils die ctoren der basisklasse aufzurufen.
Solange die abgeleitete Klasse keine eigenen dynamischen Elemente anlegt und verwaltet, stört das überhaupt nichts. Die default-generierten Methoden rufen jeweils die entsprechenden Funktionen der Basisklasse und der eigenen Member auf - und die Basismethoden sind dann dafür zuständig, die dynamischen Arrays zu verwalten.
oh genau, das hätte ich jetzt fast übersehn

natürlich wird in der abgeleiteten klasse kein speicher mehr auf dem heap angefordert, dann würd's natürlich gehen. Danke für den Tip
-
habe jetzt ein weiteres problem, wobei ich glaube, dass es in C++ nicht umsetzbar ist: ich habe jetzt der basisklasse einen member maxsize verpasst. der wird bei einer methode benötigt, die virtual ist und daher in allen abegeleiteten klassen existiert. maxsize wird weiterhin in jeder abgeleiteten klasse überschrieben, und benötigt für die eben erwähnte methode ja einen this zeiger, kann also nicht statisch sein. const kann es aber auch nicht sein, weil man es sonst im elementinitialisierer des ctors initialisieren müsste, da wirds aber schon wieder gebraucht. zum besseren verständnis mal ein bsp:
class myContainer { private: const size_t maxsize; size_t m_size; public: myContainer(const size_t size) : maxsize(1<<10), m_size(std::min(maxsize, size)) {}; };geht nicht, maxsize müsste da static sein!
class myContainer { private: size_t m_size; static const size_t maxsize = 1<<10; //... };geht auch nicht, ich will maxsize ja in jeder abgeleiteten klasse haben.
-
Wieso sollte der erste Teil nicht gehen? Btw, was zwingt dich dazu, maxsize static zu definieren?
-
CStoll schrieb:
Wieso sollte der erste Teil nicht gehen? Btw, was zwingt dich dazu, maxsize static zu definieren?
der compiler, er sagt es MUSS statisch sein, wobei ich dann die virtual methode vergessen kann ...
btw ich verwende die IDE visual studio 2005 express falls das weiterhilft
-
In den obigen Code-Schnipseln sehe ich keinen Grund, das static zu definieren. Wo und wie setzt du denn maxsize ein? (btw, static und virtual widersprechen sich ein wenig ;))
-
CStoll schrieb:
In den obigen Code-Schnipseln sehe ich keinen Grund, das static zu definieren.
glaub mir, ich auch nicht. aber leider macht compiler dann mucken...
CStoll schrieb:
Wo und wie setzt du denn maxsize ein?
eine virtual methode der basisklasse setzt es ein. das element maxsize hat in jeder abgeleiteten klasse einen anderen wert und somit arbeitet die virtuelle methode immer mit dem zur klasse passenden maxsize
CStoll schrieb:
(btw, static und virtual widersprechen sich ein wenig ;))
eben genau deswegen darf es ja nicht statisch sein!
-
CStoll schrieb:
In den obigen Code-Schnipseln sehe ich keinen Grund, das static zu definieren. ...
Ich schon :p
: Er will es in der Deklaration initialisieren und das geht IIRC nur mit "const static"s, oder ?Wie wärs mit
class myContainer { private: size_t m_size; virtual size_t maxsize() { return 1<<10; } ...ist jedenfalls const und virtual UND in der Deklaration definiert ...
Gruß,
Simon2.
-
Simon2 schrieb:
CStoll schrieb:
In den obigen Code-Schnipseln sehe ich keinen Grund, das static zu definieren. ...
Ich schon :p
: Er will es in der Deklaration initialisieren und das geht IIRC nur mit "const static"s, oder ?jo genau, das hatte ich vor. oder wenns sein muss auch noch im elementinitialisierer, aber wirklich nur wenns nich anders geht (wobei nichtmal das geht, also dort initialisieren und direkt dannach noch verwenden, bevor der eigentlich block anfängt)...
von daher glaube ich auch, dasses nur mit static const's geht.Simon2 schrieb:
Wie wärs mit
class myContainer { private: size_t m_size; virtual size_t maxsize() { return 1<<10; } ...ist jedenfalls const und virtual UND in der Deklaration definiert ...
Vielen dank für den vorschlag

so muss ich zwar die methode auch jedesmal überschreiben aber das wars dann auch schon. da das mit der konstante nicht geklappt hat, hätte ich fast die besagte methode aus der basisklasse jedesmal neu geschriben und das wär unfug!
-
Hupps,
natürlich ein const vergessen:
... virtual size_t maxsize() const { return 1<<10; } ...Allerdings musst Du mit der Technik ein wenig aufpassen, denn maxsize kannst Du nun natürlich nicht mehr "referenzieren" (also z.B. an eine Funktion übergeben, die einen "size_t const*" erwartet - bei "size_t const&" bin ich mir gerade nicht sicher)...
"Initialisierungsliste" wäre natürlich auch noch eine Idee gewesen (auf die ich nicht gekommen bin)... aber da wird's dann mit dem Überladen in abgeleiteten Klassen häßlich....
Gruß,
Simon2.