Wer in C++ mit benutzerdefinierten Objekten arbeitet, möchte mit diesen oft auch rechnen, oder deren Inhalte in der Konsole ausgeben. Wir sehen uns am Beispiel einer Vektorstruktur an, wie diverse Operatoren überladen werden können. Anschließend testen wir die Implementierung mit Hilfe mehrerer Rechenbeispiele.
Für die Umsetzung diese Beispiels ist die Headerdatei iostream
erforderlich.
1 2 |
// Header für std::cout einbinden #include <iostream> |
Wir definieren eine Struktur für einen Vektor mit drei Komponenten (Vector3)
1 2 3 4 |
// Vektorstruktur struct Vector3 { }; |
Anschließend erhält die Struktur drei Member Variablen vom Typ double (m_x
, m_y
, m_z
). Diese Variablen repräsentieren die Raumkoordinaten des Vektors. Um die Variablen mit gültigen Startwerten zu versehen, implementieren wir einen Konstruktor mit entsprechenden Default Parametern (Wert 0 für alle drei Komponenten).
1 2 3 4 5 6 7 8 |
// Komponenten des Vektors double m_x; double m_y; double m_z; // Konstruktor Vector3(double x = 0, double y = 0, double z = 0) : m_x(x), m_y(y), m_z(z) {} |
Im nächsten Schritt überladen wir den Plus Operator. Das Ergebnis einer Vektoraddition ist wiederum ein Vektor. Daher definieren wir als Rückgabetyp Vector3
. Anschließend steht das Schlüsselwort operator
, gefolgt von einem Plus Zeichen. Im nächsten Teil legen wir fest, welcher Datentyp mit unserem Vektor verrechnet werden soll. Es handelt sich dabei um ein weiteres Vector3
Objekt. Unsere Überladung führt keinerlei Veränderungen am eigenen oder am zweiten Objekt durch. Es wird lediglich ein neues Vector3 Objekt erzeugt und zurückgegeben. Daher können wir sowohl den Parameter other
als auch die Überladungsfunktion als const
definieren.
Zwei Vektoren werden addiert, indem die einzelnen Komponenten addiert werden. Wir erstellen ein Vector3
Objekt (vec
), welches durch die Übergabe des dereferenzierten this
Zeigers zu einer Kopie des aktuellen Vektorobjektes wird. Anschließend addieren wir zu den Komponenten von vec
die jeweils entsprechenden Komponenten vom zweiten Vektor (other
). Abschließend wird das neue Vektorobjekt zurückgegeben.
1 2 3 4 5 6 7 8 9 |
// Plus Operator überladen (Verktorsumme berechnen) Vector3 operator + (const Vector3& other) const { Vector3 vec (*this); vec.m_x += other.m_x; vec.m_y += other.m_y; vec.m_z += other.m_z; return vec; } |
Vektoren können auch mit einender multipliziert werden. Im Gegensatz zur Addition gibt es hier jedoch mehrere Varianten (Link zur Übersicht). Zwei davon sind das Skalarprodukt und die Skalarmultiplikation.
Im ersten Fall werden zwei Vektoren der gleichen Länge mit einander verrechnet. Es werden die jeweiligen Komponenten multipliziert und aufaddiert. Das Ergebnis ist ein Skalar, welchen wir als Typ double
zurückgeben.
Im zweiten Fall wird ein Vektor mit einem Skalar verrechnet. Dabei wird jeder einzelne Wert von Vector3 mit dem Skalar multipliziert. Das Ergebnis ist ein Objekt vom Typ Vector3
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// Stern Operator überladen (Sakalarprodukt berechnen) double operator * (const Vector3& other) const { Vector3 vec (*this); double scalar = vec.m_x*other.m_x + vec.m_y*other.m_y + vec.m_z*other.m_z; return scalar; } // Stern Operator überladen (Skalarmultiplikation berechnen) Vector3 operator * (const double& other) const { Vector3 vec (*this); vec.m_x *= other; vec.m_y *= other; vec.m_z *= other; return vec; } |
Wir haben in unserer Struktur mehrere Operatoren überladen. Nun wollen wir mit unseren Objekten rechnen und die Ergebnisse in der Konsole ausgeben. Dazu ist eine weitere Überladung erforderlich. Der Bit Shift Operator wird von std::cout
verwendet um Standardtypen auszugeben. Wollen wir diese Funktion nutzen, um unseren eigenen Datentyp ausgeben zu können, müssen wir eine entsprechende Anweisung für den Shift Operator implementieren. Die Umsetzung ist ähnlich den Überladungen, die wir zuvor durchgeführt haben. Der Rückgabetyp ist in diesem Fall vom Typ std::ostream&
. Zur besseren Erkennbarkeit der Ausgabe fügen wir am Beginn und am Ende eckige Klammern hinzu.
1 2 3 4 5 6 7 8 9 10 11 12 |
// Bit Shift Operator überladen std::ostream& operator << (std::ostream& stream, const Vector3& other) { stream << '[' << other.m_x <<", " << other.m_y << ", " << other.m_z << ']'; return stream; } |
Wir können nun in unserer Hauptroutine mehrere Anwendungen unserer Überladungen testen. Zuerst legen wir zwei Vektoren an und geben sie direkt aus. Anschließend testen wir die Addition, das Skalarprodukt und die Skalarmultiplikation. Zum Schluss verketten wir mehrere Rechenoperationen. Die Ausgabe zeigt, dass wir erfolgreich vier Operatoren überladen haben.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// Vektoren ausgeben Vector3 a(1,2,3); Vector3 b(3,2,1); std::cout << "Vektor a: " << a << '\n'; std::cout << "Vektor b: " << b << '\n'; // Vektoren addieren std::cout << a << " + "<< b << " = "<< a + b << '\n'; // Skalarprodukt berechnen std::cout << a << " * "<< b << " = "<< a*b << '\n'; // Skalarmultiplikation berechnen std::cout << b << " * "<< 10 << " = "<< b*10 << '\n'; // Berechnungen verketten std::cout << b << " * "<< 3 << " + "<< a << " = " << b*3 +a << '\n'; |
Vektor a: [1, 2, 3]
Vektor b: [3, 2, 1]
[1, 2, 3] + [3, 2, 1] = [4, 4, 4]
[1, 2, 3] * [3, 2, 1] = 10
[3, 2, 1] * 10 = [30, 20, 10]
[3, 2, 1] * 3 + [1, 2, 3] = [10, 8, 6]
Das Beispiel kann (unter Linux) mit folgendem Befehl kompiliert und ausgeführt werden:
g++ -std=c++11 cpp_operator_ueberladen.cpp && ./a.out
Das Komplette Beispiel herunterladen: cpp_operator_ueberladen.zip
Hinterlasse jetzt einen Kommentar