In C++ ist das Überladen von Operatoren ein Polymorphismus zur Kompilierungszeit. Dabei handelt es sich um die Idee, einem vorhandenen Operator in C++ eine besondere Bedeutung zu geben, ohne seine ursprüngliche Bedeutung zu ändern.
In diesem Artikel werden wir das Überladen von Operatoren in C++ anhand von Beispielen weiter diskutieren und sehen, welche Operatoren wir in C++ überladen können und welche nicht.
Überladung von C++-Operatoren
C++ hat die Fähigkeit, den Operatoren eine besondere Bedeutung für einen Datentyp zu geben; diese Fähigkeit wird als Operatorüberladung bezeichnet. Das Überladen von Operatoren ist ein Polymorphismus zur Kompilierungszeit. Beispielsweise können wir einen Operator „+“ in einer Klasse wie „String“ überladen, sodass wir zwei Zeichenfolgen verketten können, indem wir einfach + verwenden. Andere Beispielklassen, in denen arithmetische Operatoren überladen sein können, sind komplexe Zahlen, Bruchzahlen, große ganze Zahlen usw.
Beispiel:
int a; float b,sum; sum = a + b;>
Hier sind die Variablen a und b vom Typ int und float, bei denen es sich um integrierte Datentypen handelt. Daher kann der Additionsoperator „+“ den Inhalt von a und b leicht addieren. Dies liegt daran, dass der Additionsoperator + vordefiniert ist, um nur Variablen des integrierten Datentyps hinzuzufügen.
Implementierung:
C++
// C++ Program to Demonstrate the> // working/Logic behind Operator> // Overloading> class> A {> >statements;> };> int> main()> {> >A a1, a2, a3;> >a3 = a1 + a2;> >return> 0;> }> |
>
>
In diesem Beispiel haben wir drei Variablen a1, a2 und a3 vom Typ Klasse A. Hier versuchen wir, mithilfe des Operators + zwei Objekte a1 und a2 hinzuzufügen, die vom benutzerdefinierten Typ sind, d. h. vom Typ Klasse A. Dies ist nicht zulässig, da der Additionsoperator + so vordefiniert ist, dass er nur mit integrierten Datentypen funktioniert. Aber hier ist Klasse A ein benutzerdefinierter Typ, sodass der Compiler einen Fehler generiert. Hier kommt das Konzept der Operatorüberlastung ins Spiel.
Wenn der Benutzer nun möchte, dass der Operator + zwei Klassenobjekte hinzufügt, muss er die Bedeutung des Operators + so umdefinieren, dass er zwei Klassenobjekte hinzufügt. Dies geschieht mithilfe des Konzepts der Operatorüberladung. Die Hauptidee hinter der Operatorüberladung besteht also darin, C++-Operatoren mit Klassenvariablen oder Klassenobjekten zu verwenden. Die Neudefinition der Bedeutung von Operatoren ändert eigentlich nichts an ihrer ursprünglichen Bedeutung; Stattdessen haben sie zusätzlich zu ihren bestehenden eine zusätzliche Bedeutung erhalten.
Beispiel für eine Operatorüberladung in C++
C++
// C++ Program to Demonstrate> // Operator Overloading> #include> using> namespace> std;> class> Complex {> private>:> >int> real, imag;> public>:> >Complex(>int> r = 0,>int> i = 0)> >{> >real = r;> >imag = i;> >}> >// This is automatically called when '+' is used with> >// between two Complex objects> >Complex operator+(Complex>const>& obj)> >{> >Complex res;> >res.real = real + obj.real;> >res.imag = imag + obj.imag;> >return> res;> >}> >void> print() { cout << real <<>' + i'> << imag <<>'
'>; }> };> int> main()> {> >Complex c1(10, 5), c2(2, 4);> >Complex c3 = c1 + c2;> >c3.print();> }> |
>
>Ausgabe
12 + i9>
Unterschied zwischen Operatorfunktionen und normalen Funktionen
Operatorfunktionen sind die gleichen wie normale Funktionen. Der einzige Unterschied besteht darin, dass der Name einer Operatorfunktion immer der ist Operator-Schlüsselwort gefolgt vom Symbol des Operators, und Operatorfunktionen werden aufgerufen, wenn der entsprechende Operator verwendet wird.
Beispiel
C++
#include> using> namespace> std;> class> Complex {> private>:> >int> real, imag;> public>:> >Complex(>int> r = 0,>int> i = 0)> >{> >real = r;> >imag = i;> >}> >void> print() { cout << real <<>' + i'> << imag << endl; }> >// The global operator function is made friend of this> >// class so that it can access private members> >friend> Complex operator+(Complex>const>& c1,> >Complex>const>& c2);> };> Complex operator+(Complex>const>& c1, Complex>const>& c2)> {> >return> Complex(c1.real + c2.real, c1.imag + c2.imag);> }> int> main()> {> >Complex c1(10, 5), c2(2, 4);> >Complex c3> >= c1> >+ c2;>// An example call to 'operator+'> >c3.print();> >return> 0;> }> |
>
>Ausgabe
12 + i9>
Können wir alle Operatoren überlasten?
Mit Ausnahme einiger weniger können fast alle Operatoren überlastet sein. Nachfolgend finden Sie eine Liste der Operatoren, die nicht überladen werden können.
sizeof typeid Scope resolution (::) Class member access operators (.(dot), .* (pointer to member operator)) Ternary or conditional (?:)>
Operatoren, die in C++ überladen werden können
Wir können überlasten
Unäre Operatoren Binäre Operatoren Spezielle Operatoren ( [ ], (), usw.)
Unter ihnen gibt es jedoch einige Operatoren, die nicht überlastet werden können. Sie sind
Bereichsauflösungsoperator (: Elementauswahloperator Elementauswahl durch *
Zeiger auf eine Mitgliedsvariable
- Bedingter Operator (? Sizeof-Operator sizeof()
| Operatoren, die überlastet werden können | Beispiele |
|---|---|
| Binäre Arithmetik | +, -, *, /, % |
| Unäre Arithmetik | +, -, ++, — |
| Abtretung | =, +=,*=, /=,-=, %= |
| Bitweise | &, | , <> , ~ , ^ |
| Dereferenzierung | (->) |
| Dynamische Speicherzuweisung, Freigabe aufheben | Neu, löschen |
| Index | [ ] |
| Funktionsaufruf | () |
| Logisch | &, | |, ! |
| Relational | >, <, = =, = |
Warum können die oben genannten Operatoren nicht überladen werden?
1. Größe des Operators
Dies gibt die Größe des als Operanden eingegebenen Objekts oder Datentyps zurück. Dies wird vom Compiler ausgewertet und kann zur Laufzeit nicht ausgewertet werden. Die ordnungsgemäße Inkrementierung eines Zeigers in einem Array von Objekten hängt implizit vom Operator sizeof ab. Eine Änderung der Bedeutung durch Überladung würde dazu führen, dass ein grundlegender Teil der Sprache zusammenbricht.
2. Typ-ID-Operator
Dadurch erhält ein CPP-Programm die Möglichkeit, den tatsächlich abgeleiteten Typ des Objekts wiederherzustellen, auf das durch einen Zeiger oder eine Referenz verwiesen wird. Bei diesem Operator geht es darum, einen Typ eindeutig zu identifizieren. Wenn wir einen benutzerdefinierten Typ wie einen anderen Typ „aussehen“ lassen möchten, kann Polymorphismus verwendet werden, aber die Bedeutung des Typ-ID-Operators muss unverändert bleiben, sonst könnten schwerwiegende Probleme auftreten.
Dateisystem unter Linux
3. Bereichsauflösung (::) Operator
Dies hilft bei der Identifizierung und Angabe des Kontexts, auf den sich ein Bezeichner bezieht, indem ein Namespace angegeben wird. Es wird zur Laufzeit vollständig ausgewertet und arbeitet mit Namen statt mit Werten. Die Operanden der Bereichsauflösung sind Notizausdrücke mit Datentypen, und CPP verfügt über keine Syntax zum Erfassen dieser Datentypen, wenn es überladen wäre. Daher ist es syntaktisch unmöglich, diesen Operator zu überladen.
4. Zugriffsoperatoren für Klassenmitglieder (.(dot ), .* (Zeiger auf Member-Operator))
Die Bedeutung und implizite Verwendung von Zugriffsoperatoren für Klassenmitglieder lässt sich anhand des folgenden Beispiels verstehen:
Beispiel:
C++
// C++ program to demonstrate operator overloading> // using dot operator> #include> using> namespace> std;> class> ComplexNumber {> private>:> >int> real;> >int> imaginary;> public>:> >ComplexNumber(>int> real,>int> imaginary)> >{> >this>->real = real;> >this>->imaginär = imaginär;> >}> >void> print() { cout << real <<>' + i'> << imaginary; }> >ComplexNumber operator+(ComplexNumber c2)> >{> >ComplexNumber c3(0, 0);> >c3.real =>this>->real + c2.real;> >c3.imaginary =>this>->imaginär + c2.imaginary;> >return> c3;> >}> };> int> main()> {> >ComplexNumber c1(3, 5);> >ComplexNumber c2(2, 4);> >ComplexNumber c3 = c1 + c2;> >c3.print();> >return> 0;> }> |
>
>Ausgabe
5 + i9>
Erläuterung:
Die Anweisung ComplexNumber c3 = c1 + c2; wird intern übersetzt als ComplexNumber c3 = c1.operator+ (c2); um die Operatorfunktion aufzurufen. Das Argument c1 wird implizit mit übergeben '.' Operator. Die nächste Anweisung nutzt ebenfalls den Punktoperator, um auf die Memberfunktion print zuzugreifen und c3 als Argument zu übergeben.
Außerdem funktionieren diese Operatoren auch mit Namen und nicht mit Werten, und es gibt keine Möglichkeit, sie (syntaktisch) zu überladen.
5. Ternärer oder bedingter (?:) Operator
Der ternäre oder bedingte Operator ist eine Kurzdarstellung einer if-else-Anweisung. Im Operator werden die Wahr/Falsch-Ausdrücke nur auf Grundlage des Wahrheitswerts des bedingten Ausdrucks ausgewertet.
conditional statement ? expression1 (if statement is TRUE) : expression2 (else)>
Eine Funktion, die den ternären Operator für eine Klasse überlädt, sagen wir ABC, indem sie die Definition verwendet
ABC operator ?: (bool condition, ABC trueExpr, ABC falseExpr);>
wäre nicht in der Lage zu garantieren, dass nur einer der Ausdrücke ausgewertet wurde. Daher kann der ternäre Operator nicht überladen werden.
Wichtige Punkte zur Überlastung des Bedieners
1) Damit die Operatorüberladung funktioniert, muss mindestens einer der Operanden ein benutzerdefiniertes Klassenobjekt sein.
2) Zuweisungsbetreiber: Der Compiler erstellt automatisch für jede Klasse einen Standardzuweisungsoperator. Der Standardzuweisungsoperator weist alle Mitglieder der rechten Seite der linken Seite zu und funktioniert in den meisten Fällen einwandfrei (dieses Verhalten ist dasselbe wie beim Kopierkonstruktor). Weitere Einzelheiten finden Sie hier.
3) Konvertierungsoperator: Wir können auch Konvertierungsoperatoren schreiben, die zum Konvertieren eines Typs in einen anderen Typ verwendet werden können.
Beispiel:
C++
// C++ Program to Demonstrate the working> // of conversion operator> #include> using> namespace> std;> class> Fraction {> private>:> >int> num, den;> public>:> >Fraction(>int> n,>int> d)> >{> >num = n;> >den = d;> >}> >// Conversion operator: return float value of fraction> >operator>float>()>const> >{> >return> float>(num) />float>(den);> >}> };> int> main()> {> >Fraction f(2, 5);> >float> val = f;> >cout << val <<>'
'>;> >return> 0;> }> |
>
>Ausgabe
0.4>
Überladene Konvertierungsoperatoren müssen eine Mitgliedsmethode sein. Andere Operatoren können entweder die Member-Methode oder die globale Methode sein.
4) Jeder Konstruktor, der mit einem einzelnen Argument aufgerufen werden kann, fungiert als Konvertierungskonstruktor, was bedeutet, dass er auch für die implizite Konvertierung in die zu erstellende Klasse verwendet werden kann.
Beispiel:
C++
// C++ program to demonstrate can also be used for implicit> // conversion to the class being constructed> #include> using> namespace> std;> class> Point {> private>:> >int> x, y;> public>:> >Point(>int> i = 0,>int> j = 0)> >{> >x = i;> >y = j;> >}> >void> print()> >{> >cout <<>'x = '> << x <<>', y = '> << y <<>'
'>;> >}> };> int> main()> {> >Point t(20, 20);> >t.print();> >t = 30;>// Member x of t becomes 30> >t.print();> >return> 0;> }> |
>
>Ausgabe
x = 20, y = 20 x = 30, y = 0>
Quiz zur Operatorüberlastung