Templates: reinterpret_cast auf initialisierte Template-Basis-Klasse schlägt fehl
-
Hallo,
ich verwende Visual Studio 2010 und Qt unter Windows.
Da ich für den Container QList ein paar weitere Funktionen brauche, habe ich mir eine Container-Template-Klasse von QList und QListIterator abgeleitet.Aufbauend auf diesen Template-Klassen habe ich für eine Klasse DNode einen Iterator definiert, der sich von meinen definierten Template-Klassen ableitet. Ich habe mal ein Minimalbeispiel aufbereitet:
#include <QList> #include <QListIterator> //------------------------------------------------------- //Template-Deklarationen //Ableitung von QList template <class T> class dList : public QList<T*> { public: dList(T* t) { append(t); } dList(const dList<T*> *olist = NULL) {append(olist); } }; //Ableitung von QListIterator template <class T> class dListIt : public QListIterator<T*> { public: dListIt(dList<T*> *t) : QListIterator<T*> (*t) { toFront(); } }; //Node-Klasse class DNode{ public: int nodeNo; }; //Ableitung von dList mit Typ DNode class ArrDlist:public dList<DNode*>{ public: ArrDlist(); private: int sortCol; Qt::SortOrder sortOrder; }; //Iterator für die Klasse DNode class ArrDlistIt:public dListIt<DNode*> { public: ArrDlistIt(ArrDlist * p):dListIt<DNode*>( reinterpret_cast<dList<DNode*>*> (p) ) {} //C2664-Fehler }; //---------------------------- //--main-- int main(int argc, char *argv[]) { ArrDlist* array = new ArrDlist(); ArrDlistIt iter(array); }Allerdings bekomme ich eine Fehlermeldung, wenn ich im Konstruktor des Iterators versuche, den Basisklassenkonstruktor aufzurufen, obwohl ich den Typ der Template-Klasse spezifiziere und meineserachtens das auch richtig caste:
dlist.hpp:41: Fehler:C2664: 'dListIt<T>::dListIt(dList<T *> *)': Konvertierung des Parameters 1 von 'dList<T> *' in 'dList<T> *' nicht m”glich
with
[
T=DNode *
]
Die Typen, auf die verwiesen wird, sind nicht verknpft; die Konvertierung erfordert einen reinterpret_cast-Operator oder eine Typumwandlung im C- oder Funktionsformat.Ich verstehe den Fehler nicht wirklich, da ich den Typ der abgeleiteten Templateklasse bei der Vererbung definiert, also damit initialisiert habe.
Oder ist generell bei Template-Klassen der Aufruf der Basisklassen-Methoden nicht möglich, so dass ich die Methoden immer in der erbenden Klasse überschreiben muss?
Vielen Dank schon mal für eure Hilfe.
Viele Grüße,
Tobias
-
Möchtest du nicht eher von
dList<DNode>, bzw.dListIt<DNode>ableiten?Sieh dir mal die Definition des Konstruktors der Spezialisierung
dListIt<DNode*>an:dListIt(dList<DNode**> *t) : QListIterator<DNode**> (*t) { toFront(); }Du rufst ihn aber auf mit
dListIt<DNode*>( reinterpret_cast<dList<DNode*>*> (p) )Das
reinterpret_castbrauchst du hier nicht. Sobald die Typen endlich stimmen, passieren upcasts wie gewohnt implizit.
Übrigens, die Bezeichnung ist Klassentemplate, nicht Template-Klasse.
-
//Ableitung von QListIterator template <class T> class dListIt : public QListIterator<T*> { public: dListIt(dList<T*> *t) : QListIterator<T*> (*t) { toFront(); } };toFront() ist vermutlich eine Memberfunktion der Basis. Dann muss dieser Aufruf qualifiziert (QListIterator<T*>::toFront()) oder ahängig (für ADL z.B. this->toFront() ) erfolgen.
Wie Sone schon gesagt hat, hat sich vermutlich irgendwo ein * zuviel eingeschlichen.
reinterpret_cast ist immer falsch, wenn innerhalb von Klassenhierarchien gecastet werden soll.
-
Oder ist generell bei Template-Klassen der Aufruf der Basisklassen-Methoden nicht möglich[...]?
NA gut, das habe ich halb falsch erklärt.
Angenommen du hast ein Klassentemplate
A.
Und dann hast du ein KlassentemplateB, das von einer Spezialisierung vonAableitet die von einem Template-Parameter vonBabhängt, bzw. die template-id die man im base-specifier angibt ist ein dependent-name.
Um dann alle Member von der Basisklasse A<...> ohne weitere Qualifizierung (wie camper gezeigt hat) nutzen zu können, muss man jede nicht-statische Memberfunktion mitusing A<...>::foo; // foo ist der Name der Funktionund jeden inneren Typ von A (typedefs, usw.) mit
using typename A<...>::bar;deklarieren.
Beispiel:
template<typename T> struct Foo { void bar(){} // Dummy typedef T DerTyp; // Dummy-Typedef }; template<typename T> struct FooFoo : Foo<T> { /// Kommentiere eine dieser using-Deklarationen aus, und sieh was passiert using Foo<int>::bar; using typename Foo<T>::DerTyp; FooFoo() { bar(); DerTyp dieVariable; } }; int main() { FooFoo<int> b; }Edit: Gleich kommt sowieso wieder camper. :p
-
Hier ist der Standard dazu:
N3337 [temp.dep]/3 schrieb:
In the definition of a class or class template, if a base class depends on a template-parameter, the base class
scope is not examined during unqualified name lookup either at the point of definition of the class template
or member or during an instantiation of the class template or member.
-
Hallo,
vielen Dank für die schnellen Antworten. Das hat mir sehr geholfen.
Es war wirklich eine Dereferenzierung zuviel. Das Ableiten von
class ArrDlist: public dList<DNode>{ ... }reicht völlig.
Vielen Dank auch für das hilfreiche Beispiel.
Viele Grüße,
Tobias