Kursinhalt
C++ OOP
C++ OOP
Operatorüberladung
Operatorüberladung ist eine leistungsstarke Funktion in objektorientierten Programmiersprachen, die es ermöglicht, das Verhalten von Operatoren für benutzerdefinierte classes
neu zu definieren. Durch das Überladen von Operatoren können Sie benutzerdefinierte Implementierungen für Operationen mit Objekten Ihrer class
bereitstellen, was zu intuitiverem und ausdrucksstärkerem Code führt.
Die Syntax der Operatorüberladung
Das Überladen erfolgt durch das Definieren spezieller Memberfunktionen oder Freundfunktionen, 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 Form sieht wie folgt aus:
overloading.h
return_type operator operator_symbol(parameters);
Die Syntax, genauer gesagt die Anzahl der Parameter und der Rückgabetyp, hängt auch davon ab, ob Operatoren als Memberfunktionen oder als Freundfunktionen überladen werden.
Member.h
Friend.h
class Example { public: Example operator+ (const Example& other) { // Define behavior for operator+ } };
Tabelle der überladbaren Operatoren
Hier ist eine Tabelle, die alle Operatoren auflistet, die überladen werden können. Es ist jedoch wichtig zu beachten, dass es keineswegs notwendig ist, alle diese Operatoren für Ihre classes
zu überladen.
Überladen von Stream-Insertion-Operatoren
Um die Operatoren <<
und >>
für eine class
zu überladen, definiert man typischerweise eine friend-Funktion oder eine Memberfunktion, die einen Ausgabestream (std::ostream&
) bzw. Eingabestream (std::istream&
) als linken Operanden und ein Objekt der eigenen class
als rechten Operanden übernimmt. Diese Funktion formatiert dann die Daten des Objekts und überträgt sie zum oder vom Stream.
Point.h
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-Insertion-Operatoren wie <<
ermöglicht es, ein benutzerdefiniertes Ausgabeverhalten für Objekte eigener classes
zu definieren, wenn diese in einen Ausgabestream wie std::cout
ausgegeben werden. Diese Funktionalität ist besonders nützlich zur Verbesserung der Lesbarkeit und Benutzerfreundlichkeit des Codes beim Arbeiten mit benutzerdefinierten Datentypen.
Das Überladen des Operators <<
für Ausgabeströme ist üblicher als das Überladen des Operators >>
für Eingabeströme, da Eingabeoperationen mit >>
anfälliger für Fehler sein können.
Überladen arithmetischer Operatoren
Andere arithmetische Operatoren (-
, *
, /
, %
) können auf ähnliche Weise überladen werden, um benutzerdefinierte Operationen mit eigenen Typen durchzuführen.
main.cpp
#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; }
Der Operator wird als Memberfunktion der Point
-class
überladen. Er nimmt ein weiteres Point
-Objekt als Parameter entgegen und gibt ein neues Point
-Objekt zurück, das die Summe der beiden Punkte repräsentiert. Der +
-Operator kann durch -
, *
, /
oder %
ersetzt werden, wobei die Implementierungslogik entsprechend angepasst werden muss.
Inkrement und Dekrement
Sowohl die Präfix- als auch die Postfix-Inkrement- und Dekrementoperatoren (++
und --
) können für benutzerdefinierte classes
überladen werden. Beginnen wir mit der Präfix-Version:
main.cpp
#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; }
Der Dekrementoperator wird ähnlich wie der Inkrementoperator überladen, indem der --
-Operator und die Subtraktionsoperation verwendet werden.
Wie Sie sehen, ist das Überladen der Präfix-Inkrement- und -Dekrementoperatoren unkompliziert. Bei den Postfix-Varianten wird es jedoch schwieriger. Beachten Sie, dass es einen Unterschied in der Reihenfolge der Ausführung zwischen Präfix- und Postfix-Operationen gibt.
Beim Überladen von Postfix-Inkrement und -Dekrement muss auch die Reihenfolge der Ausführung implementiert werden. Dies sieht dann etwa so aus:
main.cpp
#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; }
Der ganzzahlige Parameter wird nur ohne Namen übergeben, um dem Compiler zu signalisieren, dass der Postfix-Inkrementoperator überladen wird. Dies ist notwendig, da die Deklarationen für Präfix- und Postfix-Operatoren ansonsten identisch sind.
In der Implementierung des Postfix-Inkrementoperators wird der ursprüngliche Wert des Objekts in einer temporären Variable (temp
) gespeichert. Das aktuelle Objekt wird anschließend inkrementiert, aber der Operator gibt den in temp
gespeicherten Wert zurück. Das bedeutet, dass die Variable inkrementiert wird, die Änderung jedoch erst im nächsten Ausdruck wirksam wird, da der Operator den ursprünglichen Wert zurückgibt.
Danke für Ihr Feedback!