Template Problem
-
Ich möchte eine Matrixklasse schreiben deren Werte beliebig gewählt werden können, d.h. einmal sollen die Einträge double sein können ein anderes mal zB int. Deshlab wollte ich eine Templateklasse schreiben. Soweit bin ich gekommen:
#ifndef _MATRIX_H_ #define _MATRIX_H_ template<class T> class Matrix { public: T** A; unsigned int rows,cols; Matrix( unsigned int rows, unsigned int cols ); ~Matrix(); double* sumMatrixCols(); double* sumMatrixRows(); double sumSumMatrix(); void addRowVector( double* row, unsigned int length, unsigned int rowPos ); void toString(); }; #endifUnd so sieht meine Klassenimplementation aus:
#include "Matrix.h" #include <iostream> using namespace std; Matrix::Matrix( unsigned int rows_, unsigned int cols_ ) { rows = rows_; cols = cols_; A = new T*[rows]; for( int i = 0; i < rows; ++i ) A[i] = new T[cols]; } Matrix::~Matrix() { for( int i = 0; i < cols; ++i ) delete A[i]; delete A; } double* Matrix::sumMatrixCols() { double* sumVector = new double[rows]; for( int i = 0; i < rows; ++i ) sumVector[i] = 0; for( int j = 0; j < cols; ++j ) for( int i = 0; i < rows; ++i ) sumVector[i] += this->A[i][j]; return sumVector; } double* Matrix::sumMatrixRows() { double* sumVector = new double[cols]; for( int j = 0; j < cols; ++j ) sumVector[j] = 0; for( int i = 0; i < rows; ++i ) for( int j = 0; j < cols; ++j ) sumVector[j] += this->A[i][j]; return sumVector; } double Matrix::sumSumMatrix() { double sumSum = 0; for( int i = 0; i < rows; ++i ) for( int j = 0; j < cols; ++j ) sumSum += this->A[i][j]; return sumSum; } void Matrix::addRowVector( double* row, unsigned int length, unsigned int rowPos ) { if( rows-1 < rowPos ) return; if( length > cols ) return; for( int j = 0; j < cols; ++j ) this->A[rowPos][j] = row[j]; } void Matrix::toString() { for( int i = 0; i < rows; ++i ) { cout << "i = " << i << "\n"; for( int j = 0; j < cols; ++j ) cout << this->A[i][j] << "\t"; cout << "\n"; } }Leider erhalte ich beim Kompilieren folgenden Fehler:
g++ -g -c Matrix.cpp
Matrix.cpp:6: error: ‘template<class T> class Matrix’ used without template parameters
Matrix.cpp:6: error: ISO C++ forbids declaration of ‘Matrix’ with no type
Matrix.cpp: In function ‘int Matrix(unsigned int, unsigned int)’:
Matrix.cpp:6: error: ‘int Matrix(unsigned int, unsigned int)’ redeclared as different kind of symbol
Matrix.h:5: error: previous declaration of ‘template<class T> class Matrix’
Matrix.cpp:7: error: ‘rows’ was not declared in this scope
Matrix.cpp:8: error: ‘cols’ was not declared in this scope
Matrix.cpp:9: error: ‘A’ was not declared in this scopeWas bedeutet das, bzw was mache ich falsch?
-
template<typename T> Matrix<T>::Matrix( unsigned int rows, unsigned int cols ) { }
-
Da das ja ein template ist, musst du dem Compiler das noch sagen:
template<class T> Matrix<T>::Matrix( unsigned int rows_, unsigned int cols_ ) { rows = rows_; cols = cols_; A = new T*[rows]; for( int i = 0; i < rows; ++i ) A[i] = new T[cols]; }Und das bei allen anderen Funktionen ebenfalls.
Wenn du dich mit Spezialisierung beschäftigst wirst du sehen, dass der Compiler die Information da nicht einfach aus dem Hut herzaubern kann/soll.
-
Die Summe von Ts ist übrigens auch wieder ein T.
template<typename T> class Matrix { public: typedef T value_type; value_type Sum() const { value_type sum = ... ... return sum; } };Das gleiche bei Methoden wie deiner addRow...
bei einer Matrix<int> weist du dort den ints double Werte zu.
-
Nich einen Kommentar zum Design: Du hast Dich mit
T** Adazu entschlossen, Dich selbst um die Verwaltung zu kümmern. Das bedeutet, dass ein eigener Copy-Ctor, ein eigener Zuweisungsoperator und ein eigener Destruktor her muss. Letztes ist jedenfalls Pflicht. Die anderen könnte man auch privat deklarieren, um das Kopieren zu verhindern; denn sonst wird der Compiler welche automatisch generieren, die nicht das richtige tun.Statdessen könnte man auch einfach folgendes machen:
class matrix { int m, n; std::vector<double> coeffs; std::ptrdiff_t index4ij(int i, int j) { return static_cast<std::ptrdiff_t>(i)*n+j; } // row major order public: matrix() : m(0), n(0) {} explicit matrix(int m, int n) : m(m), n(n), coeffs(std::ptrdiff_t(m)*n) {} double& operator()(int i, int j) {return coeffs.at(index4ij(i,j));} ... };Oder:
class matrix { int m, n; std::vector<std::vector<double> > coeffs; public: matrix() : m(0), n(0) {} explicit matrix(int m, int n) : m(m), n(n), coeffs(m) { for (int i=0; i<m; ++i) coeffs.at(i).resize(n); } double& operator()(int i, int j) {return coeffs.at(i).at(j);} ... };In beiden Fällen kommst Du um das Definieren von eigenen Kopierkonstruktor, Zuweisungsoperator und Destruktor rum. Toll, oder?
-
Noch etwas:
HändyÄndy schrieb:
#ifndef _MATRIX_H_ #define _MATRIX_H_Bezeichner, die mit _ anfangen oder zwei aufeinander folgende _ besitzen, sind reserviert und sollte nicht benutzt werden.
-
Besten Dank für die Hinweise der Compiler meckert nun nicht mehr.