2009-03-13 15 views
15

Ich habe ein Problem, das ich nicht wirklich verstehe. Ich habe einen Klassenknoten.C++ Klasse mit Vorlage kann seinen Konstruktor nicht finden

template<class T> 
class node { 
protected: 
    T _data; 
public: 
    node(T data); 
}; 

Dies ist in der Datei "node.h". In "node.cpp" Datei, gibt es diesen Konstruktor:

#include "node.h" 

template<class T> 
node<T>::node (T data) { 
    _data = data; 
} 

Während der Compiler keine Fehler findet, der Linker (ld) sagt mir:

/usr/bin/ld: undefinierte Symbole:

Knoten <int> :: node (int)

der komische Teil ... wenn ich den Konstruktor von .cpp in .h-Datei verschiebe, funktioniert alles gut. Wo ist das Problem?

Antwort

23

Das Problem ist, dass Vorlagen keine Klassen sind - Sie schreiben sie normalerweise nicht in zwei separate Dateien. Template-Klassen sind Code, den der Compiler Klassen generiert. Daher muss Ihr Implementierungscode effektiv inline sein, d. H. In der Kopfzeile, wie Sie festgestellt haben.

Für eine ausführlichere Erklärung von warum es so sein muss, siehe C++ FAQ Lite.

13

Als allgemeine Regel müssen Sie alle Vorlagenelemente in die Headerdatei einfügen. Vorlagen werden in einer gebrauchsfertigen Weise kompiliert, und daher muss die gesamte Definition überall verfügbar sein, wo sie verwendet wird. Durch das Einfügen des Codes in die Header-Datei wird dieses Problem gelöst.

Die einzige Zeit, in der Sie eine Vorlagendefinition in eine CPP-Datei einfügen können, ist, wenn die Vorlage nur in dieser CPP-Datei verwendet wird. Der Grund dafür ist, dass es dem Standard entspricht, dass die gesamte Definition für die Kompilierung verfügbar ist.

Durch Verschieben des Inhalts von node.cpp in node.h wird das Problem behoben.

Seltsame Szenarien

Dann wieder, können Sie auch alles, was in einer CPP-Datei setzen und auch die CPP-Datei. C++ ist auf diese Weise flexibel. Ich erwähne das nur, weil ich es vorher gesehen habe. Ich habe mir sogar den Kiefer verletzt, als er auf meinen Schreibtisch schlug.

+1

können Sie auch templatized Mitglied Funktionen eines nicht-templatized Klasse in die CPP-Datei setzen, wenn Sie sie nie an anderer Stelle gehen zu nennen (so dies durchzusetzen, sie sollte privat sein, aber sie müssen nicht sein). – rmeador

1

Wenn Sie node<int> verwenden, haben Sie wahrscheinlich node.cpp nicht eingeschlossen. Daher kann der Compiler den node<int>::node<int>-Konstruktor nicht instanziieren. In der Regel wird der Vorlagencode, einschließlich aller Implementierungen der Methoden, in die Headerdatei oder etwas davon eingefügt.

0

Wenn die Funktion nicht aufgerufen wird, gibt der Compiler keinen Code aus, und der Linker findet ihn nicht.

Sie sollten die Funktion in der Kopfzeile, wo es hingehört.

+0

Ich verstehe es immer noch nicht. Warum kann eine Vorlage keine Klasse mit einem separaten Header und dem Quellcode sein? Sagen wir, ich möchte meine eigene Liste schreiben .. Muss ich jede List Methode in die Header-Datei aufnehmen? –

+0

Ja, das ist der gebräuchlichste Weg. Sie können "List.cpp" auch am Ende von List.h. –

+0

ok dann. Ich fand es seltsam, alles in die Header-Datei aufzunehmen - der eigentliche Code ist ein bisschen länger als die paar Zeilen in der Frage (es ist ein binärer Suchbaum). –

0

implizite Instanziierung ausgeschaltet ist, müssen Sie

template class node<int>; 

irgendwo in Ihrem Code (node.cpp vielleicht)

EDIT: schlechte Antwort, es ist wahrscheinlich nicht der Fall.

+1

Wenn Sie denken, dass dies eine schlechte Antwort ist, können Sie sie löschen, bevor Sie downvoted werden. –

1

Die allgemein anerkannte Vorgehensweise besteht darin, die gesamte Implementierung in die .h-Datei zu stellen, damit die Klassen nach Bedarf aus der Vorlage generiert werden können.

Wenn Sie im Voraus wissen, mit welchen Typen Ihre Vorlage instanziiert wird, können Sie möglicherweise etwas schummeln. Stellen Sie sicher, dass Ihre .cpp-Datei einen Anwendungsfall für jeden Typ und jede Methode enthält, die Sie benötigen. Es ist wichtig, dass der Anwendungsfall hinter dem Vorlagencode steht. Z.B. für „node.cpp“, verwenden

#include "node.h" 

template<class T> 
node<T>::node (T data) { 
    _data = data; 
} 

void dummy(void) 
{ 
    node<int> intnode(0); 
    node<double> doublenode(0.0); 
} 
1
// You can put templates declaration in header and definition in source 
// node.h or wherever you include file gets included 
extern template class node<int>; 

// node.cpp or where ever source file you want to use it 
// But use it only once for each type of generated class 
template class node<int>; 
Verwandte Themen