C++ - Operatoren überladen
Transcription
C++ - Operatoren überladen
FB Informatik Prof. Dr. R.Nitsch C++ - Operatoren überladen Reiner Nitsch 8417 [email protected] Überladen von Operatoren FB Informatik Prof. Dr. R.Nitsch • Ziel: Die üblichen Operatoren (z.B. +, -, /, *, %, (), [], <<, >>, <=, >=, =, ==, …) auch auf Objekte eigener Klassen anwenden können. Beispiel: Klasse Bruch Bruch::Bruch() { z = n = 0; } Bruch::Bruch(int zahler) {z=zaehler; n=1; } Bruch::Bruch(int zaehler, int nenner) { z = zaehler; n = nenner; } Warum hier keine Referenz? void main() { Bruch b1(1,2),b2(2,3),result; result = b1.plus(b2); Bruch Bruch Bruch äquivalente Anweisungen result = b1 + b2; Bruch Bruch Bruch Rückgabe einer Referenz auf eine lokale Variable einer Fkt ist ein logischer Fehler. Bruch Bruch::plus(const Bruch& b) const { return Bruch(z*b.n+b.z*n, n*b.n); } Principle of least privilege const-correctness Methode "operator+" in kompakter Aufrufsyntax result = b1.operator+(b2); Bruch Bruch::operator+(const Bruch& b) const { return Bruch(z*b.n+b.z*n, n*b.n); } } Methode "operator+" in üblicher Aufrufsyntax lokales temporäres Objekt; wird auf Stack erzeugt, zurückgegeben, und danach dessen Destruktor aufgerufen. 11.05.2009 C++ Operatoren überladen Überladener '+' Operator 2 Überladen von Operatoren FB Informatik Prof. Dr. R.Nitsch Aufgabe: Ergänzen Sie die Klasse Bruch so, dass die folgenden Anweisungen compilieren result = b1 + Bruch 3; // Anweisung in main Was wird hier benötigt? int Bruch äquivalent result = b1.operator+(3); int Bruch implizit Typumwandlungskonstruktor Bruch(int) aufrufen result= 3 Bruch int + b1; // Anweisung in main Welches Problem? Bruch wäre äquivalent zu // Fehler: C++ läßt Überladung der Operatoren für Standardtypen nicht zu result = 3.operator+(b1); int und nicht Bruch! Abhilfe: Globale operator+ Funktion 11.05.2009 C++ Operatoren überladen 3 Globale operator-Funktionen 5.5.2009 FB Informatik Prof. Dr. R.Nitsch Beispiel: Globale operator+ Funktion Bruch operator+( int i , const Bruch& b) { // in Bruch.cpp return Bruch( i*n+b.z,b.n ); } result = 3 + b1; // Aufruf der globalen operator-Fkt. Demo: Referenzrückgabe globale Operator+ Fkt. // compiliert jetzt fehlerfrei in main besser, weil universeller, ist aber die globale Funktion Bruch operator+( const Bruch& b1, const Bruch& b2 ) { return Bruch( b1.z*b2.n+b2.z*b1n, b1.n*b2.n ); } Problem: Compiler kann jetzt nicht entscheiden, ob globale Funktion ::operator+(const Bruch&, const Bruch&) oder Bruch::operator+( const Bruch& ) aufgerufen werden soll. Bruch::operator+ löschen! Anwendung in main result = 3 + b1; entspricht Anweisung result = operator+( Bruch(3), begin ) result = b1 + 3; entspricht Anweisung result = operator+( b1 , Bruch(3) ) 11.05.2009 C++ Operatoren überladen Anwendung in main 4 Was ist bei der Überladung von Operatoren zu beachten? FB Informatik Prof. Dr. R.Nitsch • Es können keine neuen Operatoren erfunden werden • Linker Operand ist immer ein Objekt der Klasse • Die Operanden-Anzahl kann nicht geändert werden; → unär bleibt unär, binär bleibt binär • Der Vorrang eines Operators bleibt erhalten • Die Operatoren . , :: , .* , ?: und sizeof() sind nicht überladbar • Soll der linke Operand kein Objekt einer Klasse sein, dann muß eine Globale Operatorfunktion definiert werden. aber: der rechte Operand muß dann ein Klassenobjekt sein. Grund: für Standardtypen können die Operatoren nicht umdefiniert werden. 11.05.2009 C++ Operatoren überladen 5 Globale Operatorfunktionen FB Informatik Prof. Dr. R.Nitsch • Einsatzgebiete: – Der Operator ist binär und der linke Operator kein Objekt einer Klasse (z.B. '+', '*',...) – Operator soll für fremde Klasse überladen werden ohne die Klasse selbst zu ändern, z.B. operator<< für Klasse ostream (kommt gleich) • Einschränkungen: – Globale Operatorfunktionen sind nicht möglich für die Operatoren '=', '()', '[]' und '->' 11.05.2009 C++ Operatoren überladen 6 Hörsaalübung FB Informatik Prof. Dr. R.Nitsch • Aufgabe: Überladen Sie den '<<' Operator so, dass folgenden Anweisungen in main fehlerfrei compilieren. Bei Bedarf kann die Klasse Bruch auch erweitert werden. void main() { Bruch b1(2,3); cout << b1; cout << endl; } Hinweis: cout ist ein Objekt der Klasse ostream, deren Deklaration in der Header-Datei <iostream> enthalten ist. void operator<<( ostream& os, const Bruch& b ) { b.toStream(os); // "Programming by delegation" } void Bruch::toStream( ostream& os ) const { os << z << '/' << n; } Hinweis: Beide Implementierungen gehören in die Datei Bruch.cpp. Die Funktionsprototypen gehören in die Datei Bruch.h! • Wie muss die globale Funktion "operator<<" für die Klasse Bruch geändert werden, damit folgende Anweisung das gewünschte Ergebnis liefert? cout << b1 << endl; 11.05.2009 ostream& operator<<( ostream& os, const Bruch& b ) { b.toStream( os ); // "Programming by delegation" return os; } C++ Operatoren überladen 10 Hörsaalübung FB Informatik Prof. Dr. R.Nitsch • Aufgabe: Überladen Sie den '-' Operator so, dass folgende Anweisung in main compiliert werden kann: void main() { Bruch b1(2,3), b2(1/2); Bruch differenz = b1 - b2; differenz2 = 1 - b1; } Bruch operator-( const Bruch& b1, const Bruch& b2 ) { return Bruch( b1.z*b2.n - b2.z*b1.n, b1.n*b2.n ); } 11.05.2009 C++ Operatoren überladen 11