Frage zum Ueberladen von Operatoren



  • Hallo allerseits,

    ich bin relativ neu mit C++ und verzweifle an folgendem Problem:
    Bin dabei, mir eine Klasse namens matrix fuer komplexe Matrizen zu schreiben.
    Dazu muss ich in der Klasse die Operatoren +,= etc. ueberladen. Hab die mal so definiert:

    matrix operator+(matrix&);[code]
    void operator=(matrix*);
    

    und dann so implementiert:

    matrix matrix::operator+(matrix &M)
    {
       matrix C = matrix(dim);
       for (char i=0; i<dim; i++)
       {
          for (char j=0; j<dim; j++)
          {
             (C).set(get(i,j)+M.get(i,j),i,j);
          };
       };
       return (C);	
    };
    
    void matrix::operator=(matrix* M)
    {
       for (char i=0; i<dim; i++)
       {
          for(char j=0; j<dim; j++)
          {
    	 set((*M).get(i,j),i,j);
          };
       };
    };
    

    (set und get setzen bzw. liefern das entsprechende Matrixelement).
    Nun das Problem:

    matrix A;
    matrix B;
    matrix C;
    A+B;               //funktioniert
    A=B;               //funktioniert
    A = B+C;      //funktioniert nicht!
    

    Bei der letzten Zeile kommt vom Compiler der Fehler, dass der "="-Operator mit dem Argument nicht definiert ist.
    Funktionieren tut es, wenn ich fuer den "+"-Operatoren matrix& als Rueckgabe-Typ verwende:

    matrix& matrix::operator+(matrix &M)
    {
       matrix* C = new matrix(dim);
       for (char i=0; i<dim; i++)
       {
          for (char j=0; j<dim; j++)
          {
             (*C).set(get(i,j)+M.get(i,j),i,j);
          };
       };
       return *C;	
    };
    

    In dem Fall habe ich aber das Problem, dass ich mit new eine neue Matrix anlegen
    muss, die nicht mehr geloescht wird. Das fuehrt in meinem Programm, fuer die
    die Klasse benoetigt wird, recht schnell dazu, dass der Speicher ueberlaeuft 😞

    Waere toll wenn mir irgendjemand einen Tip haette, bin echt am Verzweifeln, so langsam...

    Gruß, Fabian



  • Ein Fehler hat sich eingeschlichen, tut mir leid:
    Der Gleichheitsoperator sieht so aus:

    void matrix::operator=(matrix& M)
    {
       for (char i=0; i<dim; i++)
       {
          for(char j=0; j<dim; j++)
          {
             set(M.get(i,j),i,j);
          };
       };
    };
    

    Gruß, Fabian



  • Um das "sauber" hinzubekommen könnte man folgenden Weg gehen:

    1. Copy-Konstruktor überladen (sowieso wichtig!)

    2. += Operator überladen, das würde dann so aussehen

    matrix& matrix::operator+=(const matrix& rhs)
         {
            // addiere rhs zu "this"
            return *this;
         }
    

    3. Zuweisungs(=) Operator überladen

    matrix& matrix::operator=(const matrix &rhs) {
    
        //hier zuerst auf Selbstzuweisung prüfen
        if (this != &rhs) {
         // hier wird die Kopierlogik implementiert, wobei 
         // hier auch das Löschen des Heaps des "alten" Objekts erfolgt
        }
    
        return *this;
    }
    

    4. + Operator als Nicht-Member implementieren (aber eventuell als friend)

    matrix operator+(const matrix& lhs, const matrix& rhs)
         {
             matrix ret(lhs);  // hierfür ist z.B. der Copy-Konstruktor nötig
             ret += rhs;      
             return ret; 
         }
    

    Puh, hoffe ich hab nichts vergessen 🙂



  • Liegt der Fehler hier nicht einfach darin, dass er beim operator+ eine Kopie zurèck gibt, der operator= aber eine Referenz erwartet (und das temporäre Objekt in der Form keine Adresse besitzt) Ich bin mir etwas unsicher, ob das tatsächlich einen Fehler gibt, bitte also um bestätigung/Korrektur.



  • Vielen Dank Vic86,

    dank deiner Hilfe habe ich es jetzt hinbekommen. Wuesste allerdings doch gerne
    noch, was genau mein Fehler war. Der entscheidende Punkt muesste doch sein,
    dass ich vorher den +-Operator als Member-Funktion mit nur einem Argument geschrieben habe. Versteh aber nicht, warum das einen Unterschied machen sollte.

    Verwirrte Grueße,
    Fabian



  • Siehe shinjas Beitrag: Was den Unterschied macht, ist die Tatsache, daß op= eine (nicht konstante) Referenz entgegengenommen hat und op+ einen temporären Wert zurückgibt - der Compiler darf eine Referenz nicht an einen temporären Wert binden (hängt mit deren Lebensdauer zusammen).



  • Du hattest beim Zuweisungsoperator eine nicht-konstante Referenz als Parameter angegeben, aber als Rückgabe vom Additionsoperator ein Matrixobjekt und dieses temp. Objekt würde nach dem Aufruf wieder zerstört werden.
    Da der Compiler annimmt, daß bei einer nicht-konstanten Referenz eine Änderung innerhalb der Funktion erfolgt, erzeugt er einen Fehler.

    Daher beachte bei möglichst allen Übergaben, daß du einen Parameter als "const T&" deklarierst, sofern du nicht wirklich eine Kopie oder eine Referenz benötigst.



  • Ok, jetzt hab ichs verstanden, vielen Dank!

    Fabian



  • matrix& matrix::operator=(const matrix &rhs) { 
    
        //hier zuerst auf Selbstzuweisung prüfen 
        if (this != &rhs) { 
    
         // hier wird die Kopierlogik implementiert, wobei 
         // hier auch das Löschen des Heaps des "alten" Objekts erfolgt 
    
         // WARUM SOLL HIER...
        } 
    
        return *this; 
    }
    

    ... der Heap des Altern Objekt gelöscht werden? das Alte objekt existiert doch weiter, und gilt nur als Source Objekt für das neue... ? Oder hab ic hwas übersehen?



  • Das Objekt selber existiert noch, deine alten Daten nicht mehr. Wenn die Matrix eine feste Größe hat, ist es kein Problem, die Daten zu überschreiben - bei einer variablen Größe ist es einfacher, einen neuen Speicherbereich anzulegen.



  • BorisDieKlinge schrieb:

    das Alte objekt existiert doch weiter, und gilt nur als Source Objekt für das neue... ? Oder hab ic hwas übersehen?

    Mit "das alte Objekt" ist nicht das Quellobjekt rhs gemeint, sondern das, was vor der Zuweisung in *this stand.



  • oh sorry.. haben aneinander vorbvei geredet, habe zuerst mit "altem" Objekt das "scr" objekt nicht das "dest" objekt gemeint.. dann ist klar :xmas2:


Anmelden zum Antworten