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.


Log in to reply