PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [C++]: Template-Klasse


pajofego
2006-11-03, 14:39:09
Hallo miteinander,

ich bin's mal wieder mit meinem Problem rund um C++ :redface:

Ich habe mich mal an das Thema Template herangetraut. Ziel soll sein eine Template Klasse für Matrizen zu schreiben. Leider bin ich noch nicht sehr weit gekommen, da mir der Kompiler Fehlermeldungen bringt, mit der ich momentan nichts anfangen. Daher der Gang hier zu euch Experten ;)

Der Code:

Header File:


template <class T>class clMatrix
{
private:
void Delete();
protected:
int m_iNoRows;
int m_iNoCols;
T **m_pMatrix;
virtual void Init(const T& value);
virtual void CopyValues(const clMatrix<T>& srcMatrix);
public:
clMatrix();
clMatrix(int noRows, int noCols); // defaul constructor
clMatrix(int noRows, int noCols, const T& value); // fill all entries with value
clMatrix(const clMatrix<T>& srcMatrix); // copy constructor
void Resize(int noRows, int noCols); // Resize my Matrix
int GetCols();
int GetRows();

~clMatrix(); // destructor
};


cpp-Datei:


#include "clMatrix.h"

template<class T> clMatrix<T>::clMatrix()
{
Resize(0, 0);
}

template<class T> clMatrix<T>::clMatrix(int noRows = 0, int noCols = 0)
{
Resize(noRows, noCols);
}

template<class T> clMatrix<T>::clMatrix(int noRows, int noCols, const T& value)
{
Resize(noRows, noCols);
Init(value);
}

template<class T> clMatrix<T>::clMatrix(const clMatrix<T>& srcMatrix)
{
Resize(srcMatrix.GetRows(), srcMatrix.GetCols());

}

template<class T> void clMatrix<T>::Init(const T& value)
{
for(int i = 0; i<noRows; i++)
for(int j = 0; j<noCols; j++)
m_pMatrix[i][j] = value;
}

template<class T> void clMatrix<T>::Resize(int noRows, int noCols)
{
m_iNoRows = noRows;
m_iNoCols = noCols;

if (m_pMatrix != NULL)
Delete();

m_pMatrix = new T*[noRows];
for(int i = 0; i<noRows; i++)
m_pMatrix[i] = new T[noCols];
}

template<class T> void clMatrix<T>::CopyValues(const clMatrix<T>& srcMatrix)
{
if(noCols == srcMatrix.GetCols() || noRows == srcMatrix.GetRows())
{
for(int i = 0; i<noRows; i++)
for(int j = 0; j<noCols; j++)
m_pMatrix[i][j] = srcMatrix[i][j];
}
else
{
cerr << "Matrixlängen stimmen nicht überein!" << endl;
exit(1);
}
}

template<class T> void clMatrix<T>::Delete()
{
for(int i = 0; i<noRows; i++)
delete[] m_pMatrix[i];
delete[] m_pMatrix;
}

template<class T> int clMatrix<T>::GetRows()
{
return noRows;
}

template<class T> int clMatrix<T>::GetCols()
{
return noCols;
}

template<class T> clMatrix<T>::~clMatrix()
{
Delete();
}


Sodele, wenn ich folgenden Code in meiner Main schreibe:


int main(int argc, char *argv[])
{
//...
clMatrix<double> myMatrix(2,2);
//...
}


Meckert der Compiler mit folgender Meldung, mit der ich nichts anfangen kann:confused:

1>NOC_2D.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""public: __thiscall clMatrix<double>::~clMatrix<double>(void)" (??1?$clMatrix@N@@QAE@XZ)" in Funktion "_main".
1>NOC_2D.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""public: __thiscall clMatrix<double>::clMatrix<double>(int,int)" (??0?$clMatrix@N@@QAE@HH@Z)" in Funktion "_main".

Was mache ich falsch?

Bzw. bei folgendem Code:


cout << myMatrix.GetCols() << endl;



1>NOC_2D.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""public: int __thiscall clMatrix<double>::GetCols(void)" (?GetCols@?$clMatrix@N@@QAEHXZ)" in Funktion "_main".

gibt's diesen Fehler dazu :confused:

Auch hier natürlich vollkommene Ratlosigkeit vom Coder:confused:

Für eure Mühen und Hilfe schon mal vielen Dank,

Gruß

pajofego

Corrail
2006-11-03, 14:56:00
Bei Template Klassen muss du den Source Code komplett im Header schreiben (außer du spezialisierst ein Template).

pajofego
2006-11-03, 15:11:21
Bei Template Klassen muss du den Source Code komplett im Header schreiben (außer du spezialisierst ein Template).

Ich habe das ganze natürlich anhand eines Beispieles versucht nachzubauen, da wurde aber das ganze auch nicht in einem Header reingeschrieben...getrennt in einem header und cpp file.

Einziger Unterschied, war das dort im header noch der eigene cpp included wurde

im header file
#include clMatrix.cpp

wenn ich das mache kommen ca. 1000 Fehler:mad:

Was meinst du mit einen Template spezialisieren?

pajofego
2006-11-03, 15:33:51
Jetzt habe ich header folgendes geschrieben:


#ifndef matrix_t
#define matrix_t
template <class T>class clMatrix
{
private:
void Delete();
protected:
int m_iNoRows;
int m_iNoCols;
T **m_pMatrix;
virtual void Init(const T& value);
virtual void CopyValues(const clMatrix<T>& srcMatrix);
public:
clMatrix();
clMatrix(int noRows, int noCols); // defaul constructor
clMatrix(int noRows, int noCols, const T& value); // fill all entries with value
clMatrix(const clMatrix<T>& srcMatrix); // copy constructor
void Resize(int noRows, int noCols); // Resize my Matrix
int GetCols();
int GetRows();

~clMatrix(); // destructor
};
#include "clMatrix.cpp"
#endif


Jetzt scheint er das normal zu kompilieren, zwar mit einer Menge von Fehler die ich nicht kapiere, aber Syntaxfehler der Klasse hat er schon mal gefunden. Wieso muss man das denn so machen?

Danke,

Gruß

pajofego

pajofego
2006-11-03, 16:13:43
Sorry Leute,

aber ich hänge schon wieder:

Jetzt bringt mir der Compiler ständig die gleiche Fehlermeldung (Funktionsvorlage wurde bereits definiert):

Was bedeutet das?

1>c:\eigene dateien\vspr2005\noc_2d\noc_2d\classes\clmatrix.cpp(17) : error C2995: "clMatrix<T>::clMatrix(void)": Funktionsvorlage wurde bereits definiert.
1> c:\eigene dateien\vspr2005\noc_2d\noc_2d\classes\clmatrix.h(26): Siehe Deklaration von 'clMatrix<T>::clMatrix'
1>c:\eigene dateien\vspr2005\noc_2d\noc_2d\classes\clmatrix.cpp(22) : error C2995: "clMatrix<T>::clMatrix(int,int)": Funktionsvorlage wurde bereits definiert.
1> c:\eigene dateien\vspr2005\noc_2d\noc_2d\classes\clmatrix.h(27): Siehe Deklaration von 'clMatrix<T>::clMatrix'
1>c:\eigene dateien\vspr2005\noc_2d\noc_2d\classes\clmatrix.cpp(28) : error C2995: "clMatrix<T>::clMatrix(int,int,const T &)": Funktionsvorlage wurde bereits definiert.
1> c:\eigene dateien\vspr2005\noc_2d\noc_2d\classes\clmatrix.h(28): Siehe Deklaration von 'clMatrix<T>::clMatrix'
1>c:\eigene dateien\vspr2005\noc_2d\noc_2d\classes\clmatrix.cpp(34) : error C2995: "clMatrix<T>::clMatrix(const clMatrix<T> &)": Funktionsvorlage wurde bereits definiert.
1> c:\eigene dateien\vspr2005\noc_2d\noc_2d\classes\clmatrix.h(29): Siehe Deklaration von 'clMatrix<T>::clMatrix'
1>c:\eigene dateien\vspr2005\noc_2d\noc_2d\classes\clmatrix.cpp(41) : error C2995: "void clMatrix<T>::Init(const T &)": Funktionsvorlage wurde bereits definiert.
1> c:\eigene dateien\vspr2005\noc_2d\noc_2d\classes\clmatrix.h(23): Siehe Deklaration von 'clMatrix<T>::Init'
1>c:\eigene dateien\vspr2005\noc_2d\noc_2d\classes\clmatrix.cpp(54) : error C2995: "void clMatrix<T>::Resize(int,int)": Funktionsvorlage wurde bereits definiert.
1> c:\eigene dateien\vspr2005\noc_2d\noc_2d\classes\clmatrix.h(30): Siehe Deklaration von 'clMatrix<T>::Resize'
1>c:\eigene dateien\vspr2005\noc_2d\noc_2d\classes\clmatrix.cpp(70) : error C2995: "void clMatrix<T>::CopyValues(const clMatrix<T> &)": Funktionsvorlage wurde bereits definiert.
1> c:\eigene dateien\vspr2005\noc_2d\noc_2d\classes\clmatrix.h(24): Siehe Deklaration von 'clMatrix<T>::CopyValues'
1>c:\eigene dateien\vspr2005\noc_2d\noc_2d\classes\clmatrix.cpp(77) : error C2995: "void clMatrix<T>::Delete(void)": Funktionsvorlage wurde bereits definiert.
1> c:\eigene dateien\vspr2005\noc_2d\noc_2d\classes\clmatrix.h(18): Siehe Deklaration von 'clMatrix<T>::Delete'
1>c:\eigene dateien\vspr2005\noc_2d\noc_2d\classes\clmatrix.cpp(82) : error C2995: "int clMatrix<T>::GetRows(void)": Funktionsvorlage wurde bereits definiert.
1> c:\eigene dateien\vspr2005\noc_2d\noc_2d\classes\clmatrix.h(32): Siehe Deklaration von 'clMatrix<T>::GetRows'
1>c:\eigene dateien\vspr2005\noc_2d\noc_2d\classes\clmatrix.cpp(87) : error C2995: "int clMatrix<T>::GetCols(void)": Funktionsvorlage wurde bereits definiert.
1> c:\eigene dateien\vspr2005\noc_2d\noc_2d\classes\clmatrix.h(31): Siehe Deklaration von 'clMatrix<T>::GetCols'
1>c:\eigene dateien\vspr2005\noc_2d\noc_2d\classes\clmatrix.cpp(92) : error C2995: "clMatrix<T>::~clMatrix(void)": Funktionsvorlage wurde bereits definiert.
1> c:\eigene dateien\vspr2005\noc_2d\noc_2d\classes\clmatrix.h(34): Siehe Deklaration von 'clMatrix<T>::~clMatrix

muhkuh_rs
2006-11-03, 16:21:08
Hast Du aus dem cpp file denn auch das #include "clMatrix.h" entfernt?

pajofego
2006-11-03, 16:33:01
Hast Du aus dem cpp file denn auch das #include "clMatrix.h" entfernt?

Nein. War in dem Beispiel was ich hatte auch drinnen

Wenn ich das mache, meldet mir der Compiler gleich für die erste Zeile einen Syntaxfehler:

Es fehlt ";" vor "<"

Corrail
2006-11-03, 18:46:19
Was meinst du mit einen Template spezialisieren?

Du kannst für gewisse Sachen Templates spezialisieren.

z.B.:

template<class T> my_class<T>::my_func() { ... }

my_class<float>::my_func() { ... } /* hier kannst du für float einen Spezialisierung machen. Wenn du das Template mit float instazierst, dann wird der Code verwendet und nicht der obrige */

Wieso muss man das denn so machen?

Wenn du ein Template an der Stelle X verwendest und der Kompiler kommt zu der Stelle passiert folgendes: zuerst versucht der Kompiler herauszufinden, mit welchen Typen/Parametern du das Template instanziert hast. Wenn er das getan hat, generiert er sich den Source Code on the fly. Wäre der Template-Code also nicht Im Header verfügbar, so kann er keinen Code generieren. Und woher soll die CPP Datei wissen, mit welchen Typen/Parametern dieses Template wo anders instanziert wird, damit es den Code generieren und für den Linker zur Verfügung stellen kann.

pajofego
2006-11-03, 21:38:17
Du kannst für gewisse Sachen Templates spezialisieren.

z.B.:

template<class T> my_class<T>::my_func() { ... }

my_class<float>::my_func() { ... } /* hier kannst du für float einen Spezialisierung machen. Wenn du das Template mit float instazierst, dann wird der Code verwendet und nicht der obrige */



Wenn du ein Template an der Stelle X verwendest und der Kompiler kommt zu der Stelle passiert folgendes: zuerst versucht der Kompiler herauszufinden, mit welchen Typen/Parametern du das Template instanziert hast. Wenn er das getan hat, generiert er sich den Source Code on the fly. Wäre der Template-Code also nicht Im Header verfügbar, so kann er keinen Code generieren. Und woher soll die CPP Datei wissen, mit welchen Typen/Parametern dieses Template wo anders instanziert wird, damit es den Code generieren und für den Linker zur Verfügung stellen kann.

Hi Corrail,

danke für deine Erklärung. Ich habe dann mal den ganzen Code in den Header eingefügt. Jetzt funkt es. Mich hätte es natürlich schon interessiert, wie man soetwas löst, indem man das Template in ein Header und in eine cpp teilt.

Schon mal an alle einen fetten Dank.

Gruß

pajofego

P.S.: Ich habe da noch folgende Frage:

Bei folgendem Code:


virtual void CopyValues(const clMatrix<T>& srcMatrix)
{
// greife ich auf den protected member gibt es keine Probleme
cout << srcMatrix.m_iNoCols << endl;

// versuche ich hingegen auf die öffentliche Methode zurückzugreifen
cout << (clMatrix<T> &)srcMatrix.GetCols() << endl;
// bekomme ich die Fehlermeldung:
// 'clMatrix<T>::GetCols': this-Zeiger kann nicht von 'const clMatrix<T>' in 'clMatrix<T> &' konvertiert werden
}


Ich hatte gelesen, dass mit Hilfe von "cast to avoid const problems (const -> non-const)" würde ich o.g. Problem lösen können. Leider nicht. Was ist denn hier nun falsch?

AnPapaSeiBua
2006-11-04, 09:48:10
P.S.: Ich habe da noch folgende Frage:

Bei folgendem Code:


virtual void CopyValues(const clMatrix<T>& srcMatrix)
{
// greife ich auf den protected member gibt es keine Probleme
cout << srcMatrix.m_iNoCols << endl;

// versuche ich hingegen auf die öffentliche Methode zurückzugreifen
cout << (clMatrix<T> &)srcMatrix.GetCols() << endl;
// bekomme ich die Fehlermeldung:
// 'clMatrix<T>::GetCols': this-Zeiger kann nicht von 'const clMatrix<T>' in 'clMatrix<T> &' konvertiert werden
}


Ich hatte gelesen, dass mit Hilfe von "cast to avoid const problems (const -> non-const)" würde ich o.g. Problem lösen können. Leider nicht. Was ist denn hier nun falsch?

scrMatrix ist ja als const deklariert, also darfst Du auch nur Methoden davon aufrufen, die auch const sind. Deklariere die Methode getCols() einfach als const, dann geht's. Solltest Du übrigens bei allen Methoden machen, die dein Objekt nicht verändern (const-correctness).

Nachtrag: Da Du eh schon virtuelle Methoden verwendest, mach den Destruktor auch virtual!

pajofego
2006-11-06, 20:46:43
scrMatrix ist ja als const deklariert, also darfst Du auch nur Methoden davon aufrufen, die auch const sind. Deklariere die Methode getCols() einfach als const, dann geht's. Solltest Du übrigens bei allen Methoden machen, die dein Objekt nicht verändern (const-correctness).

Nachtrag: Da Du eh schon virtuelle Methoden verwendest, mach den Destruktor auch virtual!

Hi danke für die Tipps,

jetzt funkts wieder.

Gruß

pajofego

muhkuh_rs
2006-11-07, 09:54:51
Es ergibt normalerweise wenig Sinn, ein template in Header und cpp zu teilen. Wenn doch, dann hättest Du:

1. im Header
#include "clMatrix.cpp"

2. im cpp file:
nicht #include "clMatrix.h"

3. Das cpp file nicht compilieren!!!!!

Wenn Du unbedingt bei einem template declaration und definition trennen willst, dann würde ich statt eines cpp files ebenfalls ein header file nehmen.