Operatorfunktion: Methode oder friend



  • hEY gUYS,
    1st: bin neu hier und freue mich ein vernünftiges Forum gefunden zu haben:-))
    bin noch ein Anfänger, wie der Name schon sagt
    2nd: myQuestion:
    Operatorfunktionen: wenn ich Operatoren überlade, deklariere ich diese als 'normale' Methode oder als friend-Funktion. Funktioniert doch eigentlich beides gleich gut (auf jeden Fall bei zB Vergleichsop); habe aber auch schon rausgefunden, daß das überladen des '<<' nur als friend funktioniert. Warum ist das so und wenn beides funktioniert, was ist schöner/eleganter (existiert ein Standard) ??? thanx' ahead!



  • jetzt bin ich Mitglied und antworte mir mal intuitiv selber:
    wenn ich das aktuelle Objekt verändere, nehme ich natürlich eine Methode um das überladen eines Operators zu implementieren,
    wenn ich das aktuelle Objekt nicht verändere, nehme ich eine Operatorfunktion (friend) und als deren Rückgabewert ein neues Objekt, Parameter an Operatorfunktion müßte dann eine Referenz auf ein konstantes Objekt sein (read-only-Bezeichner).
    richtig????? bitte um Antwort; thanx'!



  • Depends. Einige Operatoren müssen Member sein (operator= z.b., noch einige mehr). Für einige binäre Operatoren gibt es hier was. Generell würd ich sagen: Im Zweifel als Nicht-Member implementieren. friend muss nicht sein, wenn die öffentliche Schnittstelle der Klasse es zuläßt.

    BTW: Dass operator<< kein Member sein darf, stimmt nicht. Siehe z.B. std::basic_ostream, die hat einige überladene operator<<-Member. Du meinst wahrscheinlich, dass man einen eigenen Inserter nicht als Member der eigenen Klasse schreiben kann. Logisch, das liegt an der Reihenfolge der Argumente.

    cout << foo kann auf zwei Arten "übersetzt" werden. Entweder als Member: cout.operator<<(foo), oder als freie Funktion: operator<<(cout, foo)

    Da der Normalsterbliche keine legale Möglichkeit hat, die Klasse basic_ostream zu verändern, bleibt nur die freie Funktion. Das schließt natürlich nicht aus, dass man operator<< doch irgendwie anders überlädt ... auch wenn es nicht sehr stilvoll ist, könnte man es ja auch so gestalten, dass man foo << cout schreiben kann 😉 Oder man überlädt das Shiften zu einem gänzlich anderen Zweck, der nichts mit Strömen zu tun hat.



  • super, vielen dank!
    //ich heiße jetzt nur noch freshman
    dann gehe ich davon aus, daß auch die Operatoren += *= .... Member sein müßen.
    if nur private Attr, dann Operatorfunktion als friend?
    Was haltet ihr von dem code s.u.
    Überladung des operator<< in der Art stilvoll?
    Was mache ich denn, wenn ich zB für diese Klasse Matrix den operator+ überladen will: als Rückgabewert hätte die Funktion dann ein Objekt der Klasse MATRIX, aber dieses wird ja erst in der Funktion deklariert und der Speicher dort durch den Konstruktor dyn. allokiert, so daß ich beim Ausführen einen Fehler bekomme, bei mat3=mat1+mat2 da in der main keine Informationen zu dem Objekt mat1+mat2 bekannt sind:
    Loaded 'C:\WINNT\system32\NTDLL.DLL', no matching symbolic information found.
    Loaded 'C:\WINNT\system32\KERNEL32.DLL', no matching symbolic information found
    ich hoffe ich konnte mich ausdrücken 😞

    [cpp]
    header:
    #ifndef MATRIX_H
    #define MATRIX_H
    class MATRIX{
    private:	unsigned int numOfRows;
    	unsigned int numOfColumns;
    	int ** element;						
    public:	MATRIX(unsigned int, unsigned int);
            ~MATRIX(void);						
            int  get_numOfRows(void)const;
            int  get_numOfColumns(void)const;
            int  get_element(int, int)const;
            void set_element(int zeile, int spalte, int wert);
            void initialize(int);
            MATRIX & operator=(const MATRIX &);
            MATRIX & operator+=(const MATRIX &);
            friend ostream & operator<<(ostream &, const MATRIX &);
    };
    #endif
    
    cpp:
    MATRIX::MATRIX(unsigned int rows=1, unsigned int columns=1)		
    : numOfRows(rows), numOfColumns(columns), element(NULL){	
        element = new int * [numOfRows];	
        for(int i=0; i<numOfRows ;i++){
            element[i] = new int [numOfColumns]; 
        }
    }
    MATRIX::~MATRIX(void){
        for(int row=0; row<numOfRows ;row++){				
            delete []element[row]; 
        }
        delete []element;
    }
    .......
    MATRIX & MATRIX::operator+=(const MATRIX & matSource){
        for(int row=0; row<numOfRows ;row++){
            for(int column=0; column<numOfColumns ;column++){
                element[row][column] += matSource.element[row][column];
            }
        }
        return * this;							
    }
    MATRIX operator+(const MATRIX & mat01, const MATRIX & mat02){
        MATRIX matSum(mat01.numOfRows,mat01.numOfColumns);
        for(int row=0; row<mat01.numOfRows;row++){
            for(int column=0; column<mat01.numOfColumns ;column++){
                matSum.element[row][column] = mat01.element[row][column] +
                                              mat02.element[row][column];
            }
        }
        return matSum;
    } 
    ostream & operator<<(ostream & os, const MATRIX & matrix){
        os<<"Matrix ("<<matrix.numOfRows<<" X "<<matrix.numOfColumns<<"):"<<endl;
        for(int row=0; row<matrix.numOfRows ;row++){
            for(int column=0; column<matrix.numOfColumns ;column++){
                os<<matrix.element[row][column]<<" ";
            }
            os<<endl;
        }
        return os;
    }
    //source-ende[/cpp]
    

    thanx' a lot!!
    greetings ex-freshman07



  • Zur Matrix: Du brauchst natürlich einen Kopierkonstruktor und Zuweisungsoperator ... mit Operatoren hat das dann nicht mehr viel zu tun 😉



  • schon klar; hab ich ja auch:
    Zuweisungsoperator

    MATRIX & MATRIX::operator=(const MATRIX & matSource){	
        for(int row=0; row<numOfRows ;row++){
            for(int column=0; column<numOfColumns ;column++){
                element[row][column] = matSource.element[row][column];
            }
        }
        return * this;
    }
    

    usw.....
    aber meine Frage bezüglich der << und + Operatoren löst das doch auch nicht 😞
    Überladung des operator<< in der Art stilvoll? Ist die Verwendung von friend hier legitim?
    Wie sähe operator+ denn aus?
    (sind es zu viele Fragen auf einmal in einem thread? sorry) ⚠



  • freshman schrieb:

    schon klar; hab ich ja auch

    Wieso machst du dir dann Sorgen um die Rückgabe der Matrix? Ich geb auch zu, dass ich nicht im Entferntesten Nachvollziehen kann, was irgendwelche Symbolauflösungsfehler in der kernel.dll mit deinen Matrizen zu tun haben sollen. Meinst du nicht, dass das eine ganz andere Baustelle ist?

    Der operator<< sieht gut aus.

    operator+ scheint auch gut zu sein. Besser wär es allerdings, ihn mithilfe von += zu implementieren. Siehe den Thread, auf den ich verlinkt hatte.

    Überladung des operator<< in der Art stilvoll? Ist die Verwendung von friend hier legitim?

    Auf jeden Fall.



  • thanx' bashar!
    Danke für die Idee; ich lasse den op+ ganz weg und realisiere alles immer mit dem op+= ,denn selbst wenn ich op+ so implementiere:

    MATRIX operator+(const MATRIX & mat01, const MATRIX & mat02){
    	MATRIX matSum(mat01.numOfRows,mat01.numOfColumns);
    	matSum.initialize(0);
    	matSum += mat01;
    	matSum += mat02;
    	return matSum;
    }
    

    funktioniert es nicht. ich denke das liegt daran, daß ich wenn ich innerhalb des op+ die Matrix matSum anlege, der Konstruktor für diese dynamisch Speicherplatz anlegt.
    Dieses Objekt ist ja dann in der aufrufenden Funktion nicht mehr bekannt, da ich als Attribut

    int ** element
    

    definiert habe. Ich glaube man könnte dieses Problem nur lösen, wenn man als Attr

    int *** element
    

    nimmt, die ganze Klasse umschreibt, sich ganz viel Arbeit macht, um alles komplizieter und unleserlicher umzugestalten und dann am Ende doch nur die Funktionalität hat, daß man in der aufrufenden Funktion

    mat01 = mat02 + mat03;
    

    anstatt:

    mat01.initialize(0);
    mat01 += mat02;
    mat01 += mat03;
    

    lohnt sich wohl nicht wirklich was?



  • freshman schrieb:

    thanx' bashar!
    Danke für die Idee; ich lasse den op+ ganz weg und realisiere alles immer mit dem op+= ,denn selbst wenn ich op+ so implementiere:

    MATRIX operator+(const MATRIX & mat01, const MATRIX & mat02){
    	MATRIX matSum(mat01.numOfRows,mat01.numOfColumns);
    	matSum.initialize(0);
    	matSum += mat01;
    	matSum += mat02;
    	return matSum;
    }
    
    MATRIX operator+(const MATRIX& mat01, const MATRIX& mat02) {
      MATRIX matSum(mat01);
      matSum += mat02;
      return matSum;
    }
    

    funktioniert es nicht. ich denke das liegt daran, daß ich wenn ich innerhalb des op+ die Matrix matSum anlege, der Konstruktor für diese dynamisch Speicherplatz anlegt.

    Nein, wenn der Kopierkonstruktur richtig arbeitet (die du mir versichert hast), dann funktioniert das.



  • it work's fine!!!!!
    @Bashar: thanx',thanx' a lot! 👍


Anmelden zum Antworten