Problem mit Templateklasse und new



  • Hallo,

    ich habe da ein kleines Problem mit einer Template-Klasse, die ich erstellt habe. So wie es aussieht kann ich für die Template-Klasse keinen Speicher allozieren. Aber erstmal kurz der Source:

    // Headerdatei templateTest.hpp
    #include <iostream>
    
    using namespace std;
    class A 
    {
    	public :
    		A()
    		{
    			cout << "class A" << endl;
    		}
    };
    
    template <class T>
    class B : public A
    {
    	private :
    		T t;
    	public :
    		B();
    
    };
    
    // Sourcedatei templateTest.cpp
    #include "templateTest.hpp"
    
    template<class T> B<T>::B()
    {
    	cout << "class B" << endl;
    }
    
    // Sourcedatei main.cpp
    #include "templateTest.hpp"
    
    int main()
    {
    	A* a;
    	a=new B<int>; //hier tritt scheinbar das Problem auf
    	return 0;
    }
    

    mein makefile sieht dann wie folgt aus:

    CC = g++
    all : main.o templateTest.o
    	${CC} -o templateTest main.o templateTest.o
    
    main.o :
    	${CC} -c main.cpp
    
    templateTest.o :
    	${CC} -c templateTest.cpp
    
    clean :
    	@- rm -f *.o templateTest
    

    Nun beklagt der Linker, dass er die Referenz zu B() nicht auflösen kann.

    undefined reference to `B<int>::B()'
    

    Weiß jemand vielleicht warum g++ das Programm anstandslos kompiliert aber nicht linken kann, obwohl die Objektdateien mit den Referenzen vorhanden sind? Ich bin für jede Hilfe/Idee dankbar.



  • Template-Funktionen müssen im Header definiert werden, sonst kann der Compiler sie nicht instanziieren (dafür benötigt er sowohl die Definition als auch die Informationen, welchen Typ er einsetzen soll - die hast du aber clevererweise auf zwei CPPs verteilt).



  • Richtig, dass habe ich auch schon festgestellt. Kannst du mir denn sagen warum das so sein muss? Ich habe irgendwo mal gelesen, dass es so auch gehen soll. Dort benutzen sie aber keinen Zeiger. Wobei ich mir nicht vorstellen kann, warum es ausgerechnet am Zeiger scheitern soll.



  • Sieh doch auch mal in die FAQ
    Template in Header- und Source-Datei aufteilen
    Da gibt es auch weiterführende Links. Das hat hier übrigens nichts mit den Zeigern zu tun. Es geht prinzipiell nicht (mit den im Link erwähnten Einschränkungen).



  • Das hat etwas mit der Template-Instanziierung zu tun. Template-Funktionen und -Klassen können erst dann in "echte" Klassen umgewandelt werden, wenn sie instanziiert werden (sprich: wenn du die Template-Parameter festlegst), deshalb muß zu dem Zeitpunkt die Definition bekannt sein.

    In deinem Beispiel werden die beiden CPP-Dateien unabhängig voneinander übersetzt und später vom Linker zusammengeführt. Und da kommt das Problem ins Spiel:

    • templateTest.cpp:
      Der Compiler sieht die Definition des B-Ctors, hat aber keine Instanziierung vorliegen. Also kann er nur die syntaktische Korrektheit dieser Funktion überprüfen, aber keinen Maschinencode erzeugen (schließlich weiß er nicht, ob du später ein B<int>, B<string> oder B<own_type> verwenden willst).
      ~Im ANSI-Standard gibt es das Schlüsselwort 'export', aber kaum ein Compiler setzt es bislang um.~
    • main.cpp:
      Der Compiler sieht die Instanziierung deiner Template-Klasse, aber er hat nur die Deklaration ihrer Methoden zur Verfügung, also kann er wieder keinen Maschinencode erzeugen.

    Die Lösung dieses Problems ist (wie oben gesagt) einfach - der B-Ctor gehört auch in den Header.



  • Somit sind alle meine Fragen beantwortet. Vielen Dank. 👍


Log in to reply