Probleme mit this Zeiger
-
Hi ich hab ein Verständnissproblem mit dem this Zeiger,
und zwar genauer gesagt warum er beim Aufruf der Funktion
Matrix Matrix::testfu() das aufrufende Objekt verändert.
Sprich ein Objekt vom Typ Matrix ruft testfu auf (siehe Main),
und wird verändert, ohne das ich da meines wissens eine zuweisung mache.
Header 1:
#ifndef mymatrix_h #define mymatrix_h #include<mycomplex.h> using namespace std; class matrix{ complex **element; unsigned int rows ,columns; public: matrix(int n,int m,char type){ element = (complex **) malloc(n*sizeof(complex *)); for (int ii = 0; ii <n; ii++)element[ii] = (complex*) malloc(m *sizeof(complex)); rows =n; columns=m; switch (type){ case 'c'://type in matrix or vector for(int ii=0;ii<rows;ii++){ for(int jj=0;jj<columns;jj++){ cout<<"enter data"<<"["<<ii<<"]"<<"["<<jj<<"]: realpart :"; cin>>element[ii][jj].data[0]; cout<<"enter data"<<"["<<ii<<"]"<<"["<<jj<<"]: imagpart :"; cin>>element[ii][jj].data[1]; element[ii][jj]=complex(element[ii][jj].data[0],element[ii][jj].data[1],'r'); }//for jj cout<<endl; }//for ii break; case 'r'://random matrix or vector for(int ii=0;ii<rows;ii++){ for(int jj=0;jj<columns;jj++){ element[ii][jj].data[0]=rand()%2; element[ii][jj].data[1]=rand()%2; element[ii][jj]=complex(element[ii][jj].data[0],element[ii][jj].data[1],'r'); }//for jj }//for ii break; case 'i'://identity matrix for(int ii=0;ii<rows;ii++){ for(int jj=0;jj<columns;jj++){ if(jj==ii){element[ii][jj].data[0]=1;element[ii][jj].data[1]=0;} else{element[ii][jj].data[0]=0;element[ii][jj].data[1]=0;} element[ii][jj]=complex(element[ii][jj].data[0],element[ii][jj].data[1],'r'); }//for jj }//for ii break; case '0'://zero matrix for(int ii=0;ii<rows;ii++){ for(int jj=0;jj<columns;jj++){ element[ii][jj].data[0]=0; element[ii][jj].data[1]=0; element[ii][jj]=complex(element[ii][jj].data[0],element[ii][jj].data[1],'r'); }//for jj }//for ii break; case '1':// ones for(int ii=0;ii<rows;ii++){ for(int jj=0;jj<columns;jj++){ element[ii][jj].data[0]=1; element[ii][jj].data[1]=1; element[ii][jj]=complex(element[ii][jj].data[0],element[ii][jj].data[1],'r'); }//for jj }//for ii break; default:cout<<"choosen constr. type does not exist"<<endl; }//switch i }//::matrix(int,int,1) ~matrix(){}//destruktor matrix matrix::operator*(matrix b){ matrix c(rows,b.columns,'0'); if(columns==b.rows){//if1 for(int ii=0;ii<rows;ii++){ for(int jj=0;jj<b.columns;jj++){ for(int kk=0;kk<columns;kk++){ c.element[ii][jj]=c.element[ii][jj]+element[ii][kk]*b.element[kk][jj]; }//for kk }//for jj }//for ii }//if1 else{ cout<<"matrix dimensions do not match"<<endl;}//Katastrophe return c; }//::operator* matrix matrix::operator+(matrix b){ matrix c(rows,columns,'0'); if((columns==b.columns)&&(rows==b.rows)){//if for(int ii=0;ii<rows;ii++){ for(int jj=0;jj<columns;jj++){ c.element[ii][jj]=element[ii][jj]+b.element[ii][jj]; }//for jj }//for ii }//if1 else{cout<<"matrix dimensions do not match"<<endl;} return c; }//::operator+ matrix matrix::operator-(matrix b){ matrix c(rows,columns,'0'); if((columns==b.columns)&&(rows==b.rows)){//if1 for(int ii=0;ii<rows;ii++){ for(int jj=0;jj<columns;jj++){ c.element[ii][jj]=element[ii][jj]-b.element[ii][jj]; }//for jj }//for ii }//if1 else{cout<<"matrix dimensions do not match"<<endl;}//katastrophe return c; }//::operator- matrix matrix::operator/(complex d){ matrix c(rows, columns,'0'); for(int ii=0;ii<rows;ii++){ for(int jj=0;jj<columns;jj++){ c.element[ii][jj]=element[ii][jj]/d; }//for jj }//for ii return c; }//::operator/ matrix matrix::operator~(){ matrix c(columns, rows,'0'); for(int ii=0;ii<rows;ii++){ for(int jj=0;jj<columns;jj++){ c.element[jj][ii]=element[ii][jj]; }//for jj }//for ii return c; }// operator~ =>transpose matrix matrix::operator()(int lowerr,int upperr,int lowerc,int upperc){ if((upperr-lowerr)<0||(upperc-lowerc)<0||lowerr<=0||lowerc<=0|| (upperr-lowerr+1)>rows||(upperc-lowerc+1)>columns){cout<<"value error"<<endl;return matrix(1,1,'0');}//if else{ lowerc=lowerc-1; upperc=upperc-1; lowerr=lowerr-1; upperr=upperr-1; matrix c(upperr-lowerr+1,upperc-lowerc+1,'0'); for(int ii=lowerr;ii<=upperr;ii++){ for(int jj=lowerc;jj<=upperc;jj++){ c.element[ii-lowerr][jj-lowerc]=element[ii][jj]; }//for jj }//for ii return c; }//else }//operator() void matrix::tellme(char *type){ switch (*type){ case 'a': cout<<"dims:"<<endl<<"rows: "<<rows<<" columns: "<<columns<<endl; cout<<"data :"<<endl; for(int ii=0;ii<rows;ii++){ for(int jj=0;jj<columns;jj++){ cout<<"element: "<<ii<<" "<<jj<<endl; element[ii][jj].tellme(); }//for jj }//for ii break; case 'r': cout<<"dims:"<<endl<<"rows: "<<rows<<" columns: "<<columns<<endl; cout<<"data :"<<endl; for(int ii=0;ii<rows;ii++){ for(int jj=0;jj<columns;jj++){ cout<<element[ii][jj].data[0]<<" "; }//for jj cout<<endl; }//for ii break; case 'i': cout<<"dims:"<<endl<<"rows: "<<rows<<" columns: "<<columns<<endl; cout<<"data :"<<endl; for(int ii=0;ii<rows;ii++){ for(int jj=0;jj<columns;jj++){ cout<<element[ii][jj].data[1]<<" "; }//for jj cout<<endl; }//for ii break; default: cout<<"type wrong"<<endl;break; }//switch type }//tellme matrix matrix::testfu() const{ matrix c= *this; for(int ii=0;ii<rows;ii++){ c.element[ii][0]=complex(0,0,'p'); }//for ii return c; }//testfu };//class matrix #endif
main:
#include<iostream> #include"mymatrix.h" #include<time.h> using namespace std; int main(){ time_t t; time(&t); srand((unsigned int)t); matrix a(2,2,'r'); a.tellme("r"); a.testfu(); a.tellme("r"); system("PAUSE"); }
header 2:
#ifndef mycomplex_h #define mycomplex_h #include <math.h> using namespace std; class complex{ public: float data[4]; complex(float a,float b,char type){ switch(type){ case 'p': (b<0)?b=b*-1:b=b; (sqrt(b*b)<=.1)?b=a=0:b=b; data[2]=a; data[3]=sqrt(b*b); data[0]=b*cos(a); data[1]=b*sin(a); break; case 'r': (sqrt(a*a)<=.1)?a=0:a=a; (sqrt(b*b)<=.1)?b=0:b=b; data[0]=a; data[1]=b; data[3]=sqrt(a*a+b*b); if(a==0){ if(a==0&&b==0){data[2]=0;} else{data[2]=(b/sqrt(b*b))*1.5707;} }//if(a==0) else{ data[2]=atan(b/a); if(a<0&&b<=0){data[2]=data[2]+3.1415;} if(a<0&&b>=0){data[2]=3.1415+data[2];} if(a>0&&b<=0){data[2]=data[2];} if(a<0&&b==0){data[2]=3.1415;} }//else break; default: cout<<"type not known"<<endl; }//switch type }//konstruktor void complex::tellme(){ cout<<endl<<"realpart: "<<data[0]<<" "<<"imagpart: "<<data[1]<<" "<<"Phase: " <<data[2]<<" "<<"Abs: "<<data[3]<<endl<<endl; }//tellme complex complex::operator+(complex b){ complex c(data[0]+b.data[0],data[1]+b.data[1],'r'); return c; }//operator+ complex complex::operator-(complex b){ complex c(data[0]-b.data[0],data[1]-b.data[1],'r'); return c; }//operator- complex complex::operator*(complex b){ complex c(data[2]+b.data[2],data[3]*b.data[3],'p'); return c; }//operator* complex complex::operator/(complex b){ complex c(data[2]-b.data[2],data[3]/b.data[3],'p'); return c; }//operator/ complex complex::operator~(){ complex c(data[0],data[1]*-1,'r'); return c; }//operator~ :conjungate };//class complex #endif
-
Ich sehe keinen Kopier-Konstruktor für deine Matrix-Klasse, d.h. in der Zeile
matrix c= *this;
greift die compilergenerierte Version, die dafür sorgt, daß sich beide Matrizen die verwendeten Daten teilen.(übrigens halte ich es nicht für eine gute Idee, Speicher für eine selbstdefinierte Klasse per malloc() anzufordern - dafür wurde new erfunden)
-
Du verletzt die 3er-Regel. Zwei Optionen bleiben Dir:
(1) Füge einen korrekten Kopierkonstruktor und einen korrekten Zuweisungsoperator hinzu; denn der, der vom Compiler generiert wird tut nicht das Richtige.
(2) Verwende einfach std::vector als Datenelement. Dann sparst Du Dir einen selbstgeschriebenen Destruktor, Kopierkonstruktur und Zuweisungsoperator; denn die vom Compiler generierten Versionsn tun genau das richtige.
Warum tun die vom Compiler generierten Kopieroperationen nicht das richtige bei Dir? Nun, die Compiler generierten Kopieroperationen kopieren die Daten elementweise. Und wenn ein Zeiger kopiert wird, entsteht ein neuer Zeiger, der auf dieselben Daten zeigt. Bei Dir:
matrix matrix::testfu() const { matrix c= *this; // *this und c zeigen auf dieselben Daten! for(int ii=0;ii<rows;ii++){ c.element[ii][0]=complex(0,0,'p'); } return c; }
Wenn dagegen ein vector kopiert wird, bekommt der neue Vektor auch eine Kopie der Daten, die er sein eigen nennen kann -- seinen eigenen Speicher.
Ich würde Dir empfehlen eine Matrix so zu implementieren:
template<class T> class matrix { vector<T> coefficients; int rows, cols; size_t indexof(int r, int c) {return size_t(r)*cols+c;} public: T const& operator()(int r, int c) const {return coefficients[indexof(r,c)];} T & operator()(int r, int c) {return coefficients[indexof(r,c)];} ... };
(Destruktor, Kopierkonstruktor und Zuzweisungsoperator sind hier nicht nötig)
-
Vielen Herzlichen Dank für die Antworten, es läuft jetzt.