Linker-Problem bei Template-Methode



  • edit> Linker Problem geloest, es bleibt ein grundsaetliches Problem bei
    Verwendung von Templates..vielen Dank fuer euere Hilfe bisher !

    Hallo,
    Ich habe eine verkettete Liste geschrieben, die Template-Objekte aufnehmen soll.

    Dazu habe ich (nun) den Datenknoten zu einer Template Klasse (template <class T>
    class Component{..}) gemacht.

    In der Main-Funktion wird ein spezifisches Template-Objekt (Component<Typ1>)
    erzeugt. Dies geschieht durch einen Konstruktor der den jeweiligen Typ übergeben
    bekommt und in T speichert.
    Das funktioniert auch soweit.
    Nun zum Problem:
    Die Liste sowie der Kopf- und Endknoten sind keine Template-Klassen. Da dort
    lediglich die Methode add() mit einem template-Objekt in Berührung kommt, habe
    ich die add Funktionen zu template <class T> Funktionen gemacht.

    Also zB in HeadNode:

    class Headnode : public Node
    {
    public:
      ..
      template <class T>
      Node * add(Component<T> *t);
      ..
    }
    

    Auch Endknoten und Liste sind so aufgesetzt.
    Ebenso die Kalsse Node, nur ist diese Methode auf = 0 gesetzt, damit Node zu
    einem ADT wird, da diese nur von den erbenden Klassen überschrieben werden
    soll.

    Das Problem ist: Wenn ich nun das in main erzeugte Objekt an die Liste übergeben
    will, scheint es ein Problem zu geben.
    Der Linker sagt er könne die Referenz auf Node * Node::add(Component<Typ1> 😉
    nicht auflösen.
    Die add-Methoden sehen, wie erwähnt alle wie folgt aus:

    add(Component<T> *t){...}

    das soll so sein, weil ich dieser add-Methode beliebige Objekte übergeben
    möchte, die dann entweder delegiert oder in einem DatenElement gespeichert
    werden sollen.

    Wo könnte das Problem liegen?



  • Hast du die add-Memberfunktion in der Header-Datei implementiert? Oder in einer cpp Datei? Muss nämlich in den Header rein.



  • Hi,

    also der einfachheithalber sind Deklaration und Methoden alle Knoten und der
    Liste zur Zeit in einer Header-Datei untergebracht die in main.cpp eingebunden
    wird. Allerdings sind die add-Methoden, die einen Datenknoten erstellen und
    diesen den Wert übergeben ausserhalb der Klassendeklaration untergebracht.

    Also so bei HeadNode und der Liste (die nur delegieren)
    <nodes.hpp>

    class HeadNode{
    public:
      ..
      template <class T>
      Node * add(DataNode<T> *t){thisNext->add(t)}
      ..
    private:
      Node *thisNext;
    }
    

    Und bei TailNode und DataNode (da diese beiden ja Knoten hinzufügen sollen)

    class TailNode : public Node{
    public:
      ..
      template <class T>
      Node * add(DataNode<T> *t);
      ..
    private:
      Node *thisNext;
      T *thisData // nur im DatenKnoten
    }
    
    template <class T>
    Node * TailNode::add(DataNode<T> *t){  
      ..
      DataNode *newDataNode = new DataNode;
      // Kopier-Konstruktor dann Kopie an Liste anfügen
      ..
    }
    

    Hatte mich eben unglücklich ausgedrückt, es soll ein Datenknoten übergeben
    werden, von dem eine Kopie um entsprechende Referenzen ergänzt in die Liste
    eingefügt werden. Also nicht add(Component<T> *t) sondern add(DataNode<T> *t).
    DataNode ist die Template-Klasse, die die übergebenen Objekte (typ1, typ2 etc)
    in T ablegt.



  • Es geht weder um HeadNode::add noch um TailNode::add. Der Linker kann Node::add nicht finden. Was ist damit?



  • Die Node-Klasse soll ein ADT für die anderen Knotenklassen sein.

    Implementation ist wie folgt:

    class Node{
    public:
      ..
      template <class T>
      Node * add(DataNode<T> *t) = 0;
      ..
    }
    

    Das Schlüsselwort virtual hat der Compiler, in ähnlichem Zusammenhang, schonmal
    angemeckert. Gibt es da eine Besonderheit bei Template-Methoden?

    DataNode erbt von Node, ist aber eine Template-Klasse:

    template <class T>
    class DataNode : public Node{
      ..
    }
    

    Die Methode add(DataNode<T> *t) soll von allen erbenden Klassen überschrieben werden.



  • Nachtrag:

    Das Schlüsselwort virtual habe ich nicht, wie vorher angegeben, in Node oder den
    erbenden Klassen angegeben.
    Schreibe ich virtual vor template, teilt der Compiler mit, dass virtual nur auf
    Fuktionen angewandt werden darf. Schreibe ich das Wort vor den Rückgabewert der
    Methode, mahnt der Compiler 'illegal use of ''virtual'.



  • virtual ist nicht in verbindung mit templates erlaubt!



  • Ich habe ein weiteres Verständnis-Problem bzgl. Templates was zu einem
    Link-Fehler führt:

    Ich erzeuge in main einen Data-Knoten vom Typ1 und übergebe diesem ein Objekt
    von Typ1, welches in T gespeichert wird:

    ..
    DataNode<Typ1> *test = new DataNode<Typ1>(obj_typ1);
    
    liste.add(test);
    

    Die Zuweisung alleine geht, das hinzufügen zur liste allerdings nicht..

    Link Fehler: undefined reference to Node::add<typ1>(DataNode <typ1> *)
    

    Es soll für alle T-Elemente (typ1, typ2..) die Methode ..

    template <class T>
    ..  add(DataNode<T> *t){..}
    

    verwendet werden. Rückgabewert ist void für die Liste, Node für alle anderen.
    Die Liste erbt nicht von Node.

    Die Methode ist in Node deklariert und soll eigentlich überschrieben werden:

    class Node{
      .. 
      template <class T>
      Node * add(DataNode<T> *t) = 0;
      ..
    }
    

    Wie schaffe ich das alle DataNode-Typen derselbe Methode add(DataNode<T> *t)
    zugewiesen werden?

    Vielen Dank für euere Hilfe!



  • class Node{
      ..
      template <class T>
      Node * add(DataNode<T> *t) = 0;
      ..
    }
    

    dies würd ich am ehesten als groben unfug bezeichnen, da "=0" nur mit "virtual" zusammen funktioniert. Und da virtual nicht zusammen mit templates funktioniert ists essig mit überschreiben.



  • Danke fuer euere Hilfe!

    Ja das habe ich schon befuerchtet. Ich habe versucht der Template-Methode add die
    virtual Deklaration irgentwie aufzuzwaengen. Denn ohne diese Deklaration habe ich
    ein Problem.

    Ich brauche Node und dessen Methode add(DataNode<T> *t) als allgemeine Referenz
    auf ein Knotenobjekt.

    Gibt es eine Moeglichkeit, wie ich auf die Methode add(DataNode<T> *t) von der
    erbenden Klassen zugreifen kann?

    In Node ist jetzt add(DataNode<T> *t){}, damit kompiliert das Programm und die
    DatenKnoten werden delegiert. Allerdings nicht hinzugefuegt, da die nicht als
    virtuell deklarierbare Methode von Node aufgerufen wird und nicht die entsprechende
    des Objekts.


Anmelden zum Antworten