Kursinhalt
C++ OOP
C++ OOP
Operatorüberladung
Operatorüberladung ist ein leistungsstarkes Merkmal in objektorientierten Programmiersprachen, das es Ihnen ermöglicht, das Verhalten von Operatoren für benutzerdefinierte Klassen neu zu definieren. Durch das Überladen von Operatoren können Sie benutzerdefinierte Implementierungen für Operationen bereitstellen, die Objekte Ihrer Klasse betreffen, was zu intuitiverem und ausdrucksstärkerem Code führt.
Die Syntax der Operatorüberladung
Das Überladen wird erreicht, indem spezielle Memberfunktionen oder Freundfunktionen definiert werden, die das gewünschte Verhalten für den Operator implementieren. Die Syntax für das Überladen von Operatoren variiert je nach Operator, den Sie überladen möchten. Die allgemeine sieht so aus:
Die Syntax, oder genauer gesagt, die Anzahl der Parameter und der Rückgabetyp, hängt auch davon ab, ob Sie Operatoren als Memberfunktionen oder Freundfunktionen überladen. Betrachten Sie die folgenden zwei Beispiele:
Member
Friend
class Example { public: Example operator+ (const Example& other) { // Define behavior for operator+ } };
Die Tabelle der Operatoren, die überladen werden können
Hier ist eine Tabelle, die alle Operatoren auflistet, die überladen werden können. Es ist jedoch wichtig zu beachten, dass es zwar möglich ist, diese Operatoren zu überladen, es jedoch absolut nicht notwendig ist, alle für Ihre Klassen zu überladen.
() | function() | |
[] | array[index] | |
++ -- | ++a , a-- , etc. | |
+ - * / % | a + b , a - b , etc. | |
+= -= *= /= | a += b , a -= b , etc. | |
== != < > | a == b , a < b , etc. | |
<< >> | cout << a , cin >> a |
Wir werden uns auf die am häufigsten verwendeten Operatoren konzentrieren, einschließlich Stream-Einfügen und Extraktion, arithmetische Operatoren, Inkrement- und Dekrement-Operatoren.
Überladen von Stream-Einfügeoperatoren
Um die Operatoren <<
und >>
für eine Klasse zu überladen, definieren Sie typischerweise eine Freundfunktion oder eine Memberfunktion, die einen Ausgabestream (std::ostream&
) oder Eingabestream (std::istream&
) als linken Operanden und ein Objekt Ihrer Klasse als rechten Operanden nimmt. Diese Funktion formatiert dann die Daten des Objekts und streamt sie zum Ausgabestream.
Point
class Point { public: friend std::ostream& operator<<(std::ostream& out, const Point& point); friend std::istream& operator>>(std::istream& in, Point& point); private: int x, y; }; std::ostream& operator<<(std::ostream& out, const Point& point) { return out << "x: " << point.x << ", y: " << point.y << std::endl; } std::istream& operator>>(std::istream& in, Point& point) { return in >> point.x >> point.y; }
Das Überladen von Stream-Einfügeoperatoren, wie <<
, ermöglicht es Ihnen, benutzerdefiniertes Ausgabeverhalten für Objekte Ihrer Klassen zu definieren, wenn sie zu einem Ausgabestream, wie std::cout
, gestreamt werden. Diese Funktion ist besonders nützlich, um die Lesbarkeit und Benutzerfreundlichkeit Ihres Codes zu verbessern, wenn Sie mit benutzerdefinierten Datentypen arbeiten.
Hinweis
Das Überladen des
<<
Operators für Ausgabestreams ist häufiger als das Überladen des >> Operators für Eingabestreams, da Eingabeoperationen mit>>
fehleranfälliger sein können fehleranfälliger.
Überladen von arithmetischen Operatoren
Sie können andere arithmetische Operatoren (-
, *
, /
, %
) auf ähnliche Weise überladen, um benutzerdefinierte Operationen mit Ihren benutzerdefinierten Typen durchzuführen.
main
#include <iostream> class Point { public: Point(int xCoord, int yCoord) : x(xCoord), y(yCoord) {} Point operator+(const Point& other) { return Point(x + other.x, y + other.y); } int getX() { return x; } int getY() { return y; } private: int x, y; }; int main() { Point p = Point(2, 4) + Point(2, 6); std::cout << p.getX() << ' ' << p.getY() << std::endl; }
In diesem Beispiel überladen wir als Mitgliedsfunktion der Point Klasse. Es nimmt ein anderes Point Objekt als Parameter und gibt ein neues Point Objekt zurück, das die Summe der beiden Punkte darstellt. Sie können +
durch -
, *
, /
, %
ersetzen und die Implementierungslogik ein wenig anpassen.
Inkrement und Dekrement
Sie können sowohl die Präfix- als auch die Postfix-Inkrement- und Dekrementoperatoren (++
und --
) für Ihre benutzerdefinierten Klassen überladen. Beginnen wir mit dem Präfix:
main
#include <iostream> class Point { public: Point(int xCoord, int yCoord) : x(xCoord), y(yCoord) {} // Prefix increment operator (++point) Point& operator++() { ++x; ++y; return *this; } int getX() { return x; } int getY() { return y; } private: int x, y; }; int main() { Point p(2, 2); ++p; std::cout << p.getX() << ' ' << p.getY() << std::endl; }
Hinweis
Der Dekrementoperator wird ähnlich wie der Inkrementoperator überladen, mit dem
--
Operator und der Subtraktionsoperation.
Wie Sie sehen, ist es nicht schwer, den Präfix-Inkrement- und Dekrementoperator zu überladen. Es wird jedoch kniffliger, wenn es um den Postfix geht. Wie Sie sich erinnern, gibt es eine Reihenfolge der Ausführung von Postfix- und Präfix-Inkrement. Nehmen wir an, wir haben die Variable x
mit dem Wert 5
.
++Präfix | ++x | 6 | |
Postfix++ | x++ | 5 | |
--Präfix | --x | 4 | |
Postfix-- | x-- | 5 |
Beim Überladen von Postfix-Inkrement und -Dekrement müssen wir auch die Reihenfolge der Ausführung implementieren. Es wird ungefähr so aussehen:
main
#include <iostream> class Point { public: Point(int xCoord, int yCoord) : x(xCoord), y(yCoord) {} // Postfix increment operator (point++) Point operator++(int) { Point temp = *this; // Creating a temp variable ++(this->x); // Incrementing original Point's x ++(this->y); // Incrementing original Point's y return temp; // Returning created temp variable } int getX() { return x; } int getY() { return y; } private: int x, y; }; int main() { Point p(2, 2); p++; std::cout << p.getX() << ' ' << p.getY() << std::endl; }
Hinweis
Der ganzzahlige Parameter wird ohne Argumentnamen übergeben, um dem Compiler lediglich zu signalisieren, dass es sich um den Postfix-Inkrementoperator handelt, der überladen wird. Dies ist notwendig, da sich die Deklaration von Präfix- und Postfix-Operatoren in keiner anderen Weise unterscheidet.
In der Implementierung des Postfix-Inkrementoperators wird der ursprüngliche Wert des Objekts in einer temporären Variablen (temp) gespeichert. Während das aktuelle Objekt dann inkrementiert wird, ist der vom Operator zurückgegebene Wert derjenige, der in temp gespeichert ist. Somit wird die Variable inkrementiert, aber die Inkrementierung wirkt sich erst im nächsten Ausdruck aus, da der Operator den ursprünglichen Wert zurückgibt.
Danke für Ihr Feedback!