Operatoren für Matrix-Rechnungen überladen



  • Hallo zusammen,
    google kann mir ausnahmsweise mal nicht helfen, bzw. ich komm mit den google-Lösungen nicht weiter.
    Ich schreibe gerade eine Matrix-Klasse und möchte gerne folgendes ermöglichen:

    Matrix A(m,n); //m x n Matrix
    //Matrix A mit Werten füllen
    Matrix B(m,n);
    B=A+A;

    Mein bisheriger Code sieht wie folgt aus, ich würde mich freuen, wenn sich das einer angucken würde:

    Matrix::Matrix(unsigned int m_, unsigned int n_):m(m_),n(n_)
    {
    	unsigned int i,j;
    
    	daten = new int*[m];
    	for(i=0; i<m; i++){
    		daten[i] = new int[n];
    		for(j=0; j<n; j++)
    			daten[i][j] = 0;
    	}
    }
    
    Matrix::~Matrix(){
    	unsigned int i;
    
    	for(i=0; i<m; i++){
    		delete daten[i];
    	}
    	delete daten;
    }
    
    Matrix Matrix::operator+(const Matrix& A){
    
    	Matrix Tmp(m,n);
    	unsigned int i,j;
    	for(i=0; i<m; i++){
    		for(j=0; j<n; j++){
    			Tmp.daten[i][j] = daten[i][j] + A.daten[i][j];
    		}
    	}
    	return Tmp;
    }
    
    Matrix& Matrix::operator =(const Matrix& A){
    
    	unsigned int i,j;
    	for(i=0; i<m; i++){
    		for(j=0; j<n; j++){
    			daten[i][j] = A.daten[i][j];
    		}
    	}
    	return *this;
    }
    

    Damit ist mein Ziel aber nicht erreichbar. Es gibt keine Fehlermeldung, aber es entweder stürzt das Programm ab (vermutlich beim destructor) oder es stehen zufällige Werte im Ergebnis.
    D.h. ich vermute, ich behandel meinen Speicher falsch 😉

    Gruß,
    wetho



  • Zumindest solltest du aus "delete" "delete[]" machen.

    Drehleiter


  • Mod

    Gibt es einen speziellen Grund, warum du nicht so etwas wie vector für die Daten nimmst?



  • Weiterhin wird ein CopyKonstruktor benötigt.
    Die beiden gezeigten Operatoren funktionieren ja auch nur wenn beide Matrizen gleich groß sind.
    Das ist beim operator+ ja auch nötig, beim Zuweisungsoperator aber nicht (wenn man ihn anders designt).
    Ich würde den operator+ auch noch zu einer globalen Funktion machen.



  • Erstmal danke an Drehleiter, da hast du natürlich Recht^^
    @SeppJ: Nee, gibts nicht, ich hab einfach nicht dran gedacht, aber kann man mein Vorhaben denn auch mit meinem Array-Kram realisieren?



  • @Braunstein: Den Fall unterschiedlicher Größen hab ich erstmal per Fehlerabfrage aussortiert... Oder brauch ich den CopyConstructor auch, wenn man von gleichgroßen Matrizen ausgehen kann?


  • Mod

    wetho schrieb:

    aber kann man mein Vorhaben denn auch mit meinem Array-Kram realisieren?

    Ja. Eigentlich sieht es auch gar nicht so verkehrt aus bis auf den fehlenden Copy-Konstruktor und das delete ohne [].

    wetho schrieb:

    Oder brauch ich den CopyConstructor auch, wenn man von gleichgroßen Matrizen ausgehen kann?

    Den brauchst du immer. Google mal nach der Regel der großem Drei.

    Wenn du es ein bisschen abstrakter haben willst: Du könntest ein Matrixtemplate machen, bei dem die Größe ein Templateparameter ist. Eine Matrix sollte ihre Größe schließlich nicht selber ändern können. Dann übernimmt der Compiler für dich die Prüfung ob die Größen passen.



  • wetho schrieb:

    Matrix A(m,n); //m x n Matrix
    //Matrix A mit Werten füllen
    Matrix B(m,n);
    B=A+A;

    Das ist ein schönes Beispiel für "Wie man es nicht machen sollte".
    So sollte das aussehen:

    Matrix A(m,n);  //m x n Matrix
    //Matrix A mit Werten füllen
    Matrix B = A+A;
    

    Dies spart typischerweise unnötiges Kopieren.
    Ich kann übrigens Boost.uBLAS empfehlen. Es dauert aber eine Weile, bis man sich damit zurecht findet.



  • Wenn du es ein bisschen abstrakter haben willst: Du könntest ein Matrixtemplate machen, bei dem die Größe ein Templateparameter ist. Eine Matrix sollte ihre Größe schließlich nicht selber ändern können. Dann übernimmt der Compiler für dich die Prüfung ob die Größen passen.

    Vor allem entfällt dann das dynamische Anfordern von Speicher:

    template<int n, int m,typename T=int>
    class Matrix{
         T[n][m];     
         // usw...
    };
    
    Matrix<4,4> m;     // find ich persönlich schöner als Matrix m(4,4)
    Matrix<2,2,float> m;
    

    Zumeist sind die Dimensionen der Matrix schon zur Compilezeit bekannt. Von daher ist diese Variante womöglich besser geeignet.



  • Guten Abend!

    Vielen Dank für die Antworten, ich werd' mal sehen, wie ich damit umgehen werde. Ich werd' mich dann nochmal melden.



  • Hab mich letztendlich für folgende Lösung entschieden:
    (mit copy-Konstruktor und nicht mit Templates realisiert)

    Matrix::Matrix(unsigned int rows_, unsigned int columns_)
    :rows(rows_),columns(columns_)
    {
    	unsigned int i,j;
    
    	daten = new double*[rows];
    	for(i=0; i<rows; i++){
    		daten[i] = new double[columns];
    		for(j=0; j<columns; j++)
    			daten[i][j] = 0;
    	}
    }
    
    Matrix::Matrix(const Matrix& A):rows(A.rows),columns(A.columns)
    {
    	unsigned int i,j;
    
    	daten = new double*[rows];
    	for(i=0; i<rows; i++){
    		daten[i] = new double[columns];
    		for(j=0; j<columns; j++){
    			daten[i][j] = A.daten[i][j];
    		}
    	}
    }
    
    Matrix::~Matrix(){
    	unsigned int i;
    
    	for(i=0; i<rows; i++){
    		delete[] daten[i];
    	}
    	delete daten;
    }
    
    Matrix Matrix::operator+(const Matrix& A) const{
    	if(rows!=A.rows || columns!=A.columns){
    		cout << "Fehler bei Matrixaddition";
    		return *this;
    	}
    
    	Matrix Tmp(rows,columns);
    	unsigned int i,j;
    	for(i=0; i<rows; i++){
    		for(j=0; j<columns; j++){
    			Tmp.daten[i][j] = daten[i][j] + A.daten[i][j];
    		}
    	}
    	return Tmp;
    }
    
    Matrix Matrix::operator*(const Matrix& A) const{
    	if(columns!=A.rows){
    		cout << "Fehler bei Matrixmultiplikation";
    		return *this;
    	}
    
    	unsigned int i,j,k;
    	double tmpsum;
    
    	Matrix Tmp(rows,A.columns);
    	for(i=0; i<rows; i++){
    		for(j=0; j<A.columns; j++){
    			tmpsum = 0;
    			for(k=0; k<columns; k++){
    				tmpsum += daten[i][k]*A.daten[k][j];
    			}
    			Tmp.daten[i][j] = tmpsum;
    		}
    	}
    	return Tmp;
    }
    
    void Matrix::operator =(const Matrix& A) {
    	unsigned int i,j;
    	if (rows != 0) {
    		for (i=0; i<rows; i++) {
    			delete [] daten[i];}
    		delete [] daten;
    	}
    	rows = A.rows;
    	columns = A.columns;
    	daten = new double*[rows];
    	for (i=0; i<rows; i++) {
    		daten[i] = new double[columns];
    		for (j=0; j<columns; j++)
    			daten[i][j] = A.daten[i][j];
    	}
    }
    

    Danke nochmal für die Hilfe.


Anmelden zum Antworten