Templates
-
Hab hier gerade ein problem beim Binden von Funktionen meiner Template Klasse.
wenn ich sie in einem externen Modul definiere können diese nicht aufgelöst werden. Wenn ich sie in die header packe, in der die Klasse definiert ist funktioniert das ganze wieder. Kann mir jemand sagen warum?
-
Ja, das ist ganz normal. Wenn der Compiler ein Template instanziert, muss er die vollständige Definition des Templates kennen. Es gibt im Sprachstandard das Schlüsselwort "export", um das zu vermeiden, aber kaum ein Compiler beherrscht es.
-
ein klassentemplate ist keine klasse und ein funktionstemplate keine funktion. erst das 'instantiieren' macht daraus eine klasse bzw. funktion. schon damit muss eigentlich klar sein, warum die definition eines templates allein in einer ÜE nicht genügt, wenn dieses in einer zweiten ÜE benutzt werden soll. selbst wenn das template an sich für den linker sichtbar wäre, so bezeichnet es nicht die entität, auf die man sich letztlich beziehen will. es gibt drei auswege:
- definition des templates in allen ÜEs, die es benutzen (also im header)
- benutzung von export (das ist nicht nur für den compilerbauer schwer zu implementieren sondern auch mit einigen fallstricken versehen)
- definition und explizite instantiierung in einer ÜE (hier muss man allerdings wissen, welche instanzen gebraucht werden)
-
Hallo Camper,
Da ich gerade am lernen von C++ bin und bei den Templates das gleiche Problem habe wie der OT:
Heisst das im Klartext dass ich die Definition und Deklaration von Generischen Klassen nicht wie üblich trennen kann? Ich versuche gerade einen generischen Stack zu programmieren der wie folgt aufgeteilt ist:
Stack.h: Deklaration der generischen Klasse
Stack.cpp: Definition der Klassenmethoden (inkludiert Stack.h)
Main.cpp: Instanziiert die generische Klasse stack mittels:Stack *pStack<int> = new Stack<int>( 100 );
(inkludiert ebenfalls Stack.h)
Der Linker meldet allerdings dass der Konstruktor nicht gefunden werden kann. Verschiebe ich alle Definitionen in die Deklaration hinein, wird sauber gelinkt und alles ist bestens.
Zur Referenz hab ich mal untenstehend den gesamten Code angehängt:
stack.h:
#ifndef __STACK_H #define __STACK_H using namespace std; template<class T> class Stack { private: T *m_pStack; int m_nCurStackPos, m_nStackSize; public: Stack( int ) ~Stack(); bool Push( const T& ); T Pop( void ); }; #endif
stack.cpp:
#include <iostream> #include "Stack.h" using namespace std; template<class T> Stack<T>::Stack( int nStackSize ) { cout << "Stack Constructor" << endl; m_nStackSize = nStackSize; m_nCurStackPos = -1; m_pStack = new T[nStackSize]; } template<class T> Stack<T>::~Stack() { cout << "Stack destructor" << endl; delete[] m_pStack; } template<class T> bool Stack<T>::Push( const T &pValue ) { if( m_nCurStackPos < ( m_nStackSize -1 )) { m_pStack[++m_nCurStackPos] = pValue; return( true ); } return( false ); } template<class T> T Stack<T>::Pop( void ) { if( m_nCurStackPos >= 0 ) { return( m_pStack[m_nCurStackPos--] ); } else { return( T() ); } }
main.cpp:
#include <iostream> #include "Stack.h" using namespace std; int main( int argc, char* argv[] ) { Stack<int> *stack = new Stack<int>( 10 ); for( int i = 0; i < 10; i ++ ) { stack->Push( i ); } for( int i = 0; i < 10; i ++ ) { cout << stack->Pop() << endl; } return( 0 ); }
Könnte mir bitte jemand das erklären, ich komm aus der Java Welt und C++ ist in diesem bereich noch ziemliches Neuland.
Danke und Grüsse,
Egon
-
Camper hat doch einen Beitrag über Deinem erklärt, warum das so sein muss?!?
-
Hi,
ja hat er, mir als C++ Neuling ist aber dennoch nicht klar, was ich an meinem Codebeispiel falsch mache. Ich binde den Header mit der Deklaration in jeder Quellcodedatei ein, in der ich das Template benutze.
Desweiteren kann ich mit dem Begriff ÜE nicht wirklich was anfange, das hab ich leider vergessen zu schreiben (ÜE=Übergeordnete Einheit?).
Grüsse, Egon
-
ÜE = Übersetzungseinheit (Eine .cpp-Datei inkl. aller in ihr verwendeten Header)
Du machst nichts falsch. Wenn Du alle Definitionen in die Header packst, funktioniert es doch nach Deiner eigenen Aussage. Warum es "klassisch getrennt" nicht funktioniert, steht weiter oben zweimal.
-
Hallo LordJaxom,
danke für die Info, jetzt ist mir das ganze klar!
Grüsse, Egon