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 verknpft; 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_cast brauchst du hier nicht. Sobald die Typen endlich stimmen, passieren upcasts wie gewohnt implizit.
    Übrigens, die Bezeichnung ist Klassentemplate, nicht Template-Klasse. 😉


  • Mod

    //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 Klassentemplate B , das von einer Spezialisierung von A ableitet die von einem Template-Parameter von B abhä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 mit

    using A<...>::foo; // foo ist der Name der Funktion
    

    und 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


Anmelden zum Antworten