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