Wahl der Leser
Populäre Artikel
Operatorüberladung in C++. Anwendungsmethoden
In haben wir uns mit den grundlegenden Aspekten der Verwendung der Operatorüberladung befasst. In diesem Artikel werden Ihnen überladene C++-Operatoren vorgestellt. Jeder Abschnitt ist durch Semantik gekennzeichnet, d.h. erwartetes Verhalten. Darüber hinaus werden typische Möglichkeiten zur Deklaration und Implementierung von Operatoren aufgezeigt.
In den Codebeispielen gibt X den benutzerdefinierten Typ an, für den der Operator implementiert ist. T ist ein optionaler Typ, entweder benutzerdefiniert oder integriert. Die Parameter des Binäroperators werden lhs und rhs genannt. Wenn ein Operator als Klassenmethode deklariert ist, wird seiner Deklaration das Präfix X:: vorangestellt.
Die generierte Anweisung kopiert/verschiebt einfach das angegebene Element, wenn eine solche Operation zulässig ist.
Wenn „operator+“ vorhanden ist, ist es normalerweise sinnvoll, auch „operator+=“ zu überladen, um die Notation „a += b“ anstelle von „a = a + b“ zu verwenden. Wenn „operator+=“ nicht überladen ist, sieht die Implementierung etwa so aus:
X-Operator+ (X const& lhs, X const& rhs) ( // ein neues Objekt erstellen, das die Summe von lhs und rhs darstellt: return lhs.plus(rhs); )
Darüber hinaus kann der Typ des linken Operanden eine beliebige Klasse sein, die sich wie ein E/A-Objekt verhalten soll, d. h. der rechte Operand kann ein integrierter Typ sein.
MyIO& MyIO::operator<< (int rhs) { doYourThingWith(rhs); return *this; }
Die zweite Implementierung von „operator!=“ vermeidet Wiederholungen des Codes und eliminiert mögliche Unklarheiten bezüglich zweier Objekte.
Operator implementieren > Operator verwenden< или наоборот обеспечивает однозначное определение. operator<= может быть реализован по-разному, в зависимости от ситуации . В частности, при отношении строго порядка operator== можно реализовать лишь через operator< :
Bool-Operator== (X const& lhs, X const& rhs) ( return !(lhs< rhs) && !(rhs < lhs); }
Dabei ist X der intelligente Zeiger, V der Typ, auf den X zeigt, und T der Typ, auf den der Feldzeiger zeigt. Es überrascht nicht, dass dieser Operator selten überlastet ist.
Diese Deklarationen sehen seltsam aus, weil ihnen ein Rückgabetyp fehlt. Es ist Teil des Operatornamens und wird nicht zweimal angegeben. Es sei daran erinnert, dass eine große Anzahl versteckter Umwandlungen zu unerwarteten Fehlern im Programm führen kann.
Diese Operatoren unterscheiden sich grundlegend von allen oben genannten, da sie nicht mit benutzerdefinierten Typen funktionieren. Ihre Überlastung ist sehr komplex und wird daher hier nicht betrachtet.
Der Grundgedanke ist dieser: Überlasten Sie Operatoren nicht, nur weil Sie wissen, wie es geht. Überladen Sie sie nur in den Fällen, in denen es natürlich und notwendig erscheint. Denken Sie jedoch daran: Wenn Sie einen Operator überlasten, müssen Sie auch andere überlasten.
Guten Tag!
Der Wunsch, diesen Artikel zu schreiben, entstand nach dem Lesen des Beitrags, da viele wichtige Themen darin nicht behandelt wurden.
Das Wichtigste, an das Sie denken sollten, ist, dass die Überladung von Operatoren nur eine bequemere Möglichkeit zum Aufrufen von Funktionen ist. Lassen Sie sich also nicht von der Überlastung von Operatoren mitreißen. Es sollte nur verwendet werden, wenn es das Schreiben von Code erleichtert. Aber nicht so sehr, dass es das Lesen erschwert. Wie Sie wissen, wird Code schließlich viel häufiger gelesen als geschrieben. Und vergessen Sie nicht, dass Sie niemals Operatoren zusammen mit integrierten Typen überladen dürfen; die Möglichkeit der Überladung besteht nur für benutzerdefinierte Typen/Klassen.
In den meisten Fällen geben Operatoren (außer bedingte) ein Objekt oder einen Verweis auf den Typ zurück, zu dem seine Argumente gehören (wenn die Typen unterschiedlich sind, entscheiden Sie, wie Sie das Ergebnis der Operatorauswertung interpretieren).
Wie Sie sehen, wird zu Beginn der Funktion eine Prüfung auf Selbstzuweisung durchgeführt. Im Allgemeinen ist Selbstaneignung in diesem Fall harmlos, aber die Situation ist nicht immer so einfach. Wenn das Objekt beispielsweise groß ist, können Sie viel Zeit durch unnötiges Kopieren oder die Arbeit mit Zeigern verschwenden.
Warum so? Erstens sind einige Betreiber zunächst eingeschränkt. Wenn es keinen semantischen Unterschied in der Definition eines Operators gibt, ist es im Allgemeinen besser, ihn als Klassenfunktion zu entwerfen, um die Verbindung hervorzuheben. Außerdem ist die Funktion inline. Darüber hinaus kann es manchmal erforderlich sein, den linken Operanden als Objekt einer anderen Klasse darzustellen. Das wohl auffälligste Beispiel ist die Neudefinition<< и >> für I/O-Streams.
Manchmal möchten Sie kreativ sein und Ihren Code für sich und andere einfacher machen. Für sich selbst schreiben, für andere verstehen. Nehmen wir an, wenn wir in unserem Programm häufig auf die Funktion stoßen, eine Zeile am Ende einer anderen hinzuzufügen, können wir dies natürlich auf unterschiedliche Weise implementieren. Und wenn wir in einem Teil unseres Codes beispielsweise Folgendes schreiben:
Char str1 = "Hallo"; char str2 = "Welt!"; str1 + str2;
und als Ergebnis erhalten wir die Zeichenfolge „Hallo Welt!“ Wäre das nicht toll? Nun, bitte! Heute lernen Sie, dem Computer zu „erklären“, dass Sie mit dem +-Operator nicht zwei Zahlen, sondern zwei Zeichenfolgen addieren möchten. Und die Arbeit mit Strings ist meiner Meinung nach eines der erfolgreichsten Beispiele, um das Thema „Operator Overloading“ zu verstehen.
Beginnen wir mit dem Üben. In diesem Beispiel überladen wir den Operator „+“ und zwingen ihn, den Inhalt einer anderen Zeile an eine Zeile anzuhängen. Nämlich: Wir werden aus vier einzelnen Zeilen einen Teil eines uns allen bekannten Gedichts von A. S. Puschkin zusammenstellen. Ich rate Ihnen, Ihre Entwicklungsumgebung zu öffnen und dieses Beispiel neu zu schreiben. Wenn Sie nicht alles im Code verstehen, machen Sie sich keine Sorgen, detaillierte Erklärungen finden Sie weiter unten.
#enthalten
Lass es uns herausfinden:
Wir haben etwas Neues im Code gesehen Zeile 16 Void-Operator +(char*); Hier haben wir einen Prototyp einer Klassenmethode deklariert, in der wir unseren +-Operator überladen. Um einen Operator zu überladen, müssen Sie den reservierten Wortoperator verwenden. Es sieht so aus, als würden Sie eine reguläre Funktion definieren: void Operator+ () (//Code) Im Hauptteil dieser Funktion platzieren wir Code, der dem Compiler mitteilt, was der +-Operator (oder ein anderer Operator) tun wird. Ein überladener Operator führt die für ihn angegebenen Aktionen nur im Rahmen der Klasse aus, in der er definiert ist. Unten, in Zeilen 20 - 23 Wir legen bereits fest, welche Rolle + in unserer Klasse spielen wird. Nämlich mit der Funktion strcat(str, s); Es wird den Inhalt der Zeichenfolge s, die wir per Zeiger übergeben haben, an das Ende der Zeichenfolge str anhängen. Zeilen 17, 25 – 28 Dies ist eine reguläre Klassenmethode, die die Klassenzeichenfolge auf dem Bildschirm anzeigt. Wenn Sie nicht wissen, wie Sie Klassenmethoden außerhalb des Klassenkörpers definieren, d. h. einen solchen Moment wie void StringsWork::getStr() (//definition), dann sollten Sie zuerst hierher gehen. Weiter bereits in der Hauptfunktion main() , in Zeilen 34 - 37, erstellen wir vier Zeiger auf Strings und weisen jedem von ihnen die erforderliche Menge an Speicher zu, wobei wir nicht vergessen, dass wir für das Zeichen „\0“ auch eine Zelle reservieren müssen char *str1 = new char ; . Dann kopieren wir den Text mit der Funktion strcpy() hinein und zeigen ihn auf dem Bildschirm an - Zeilen 39 - 47. Und in Zeile 49 Erstellen Sie ein Klassenobjekt. Beim Erstellen funktioniert der Klassenkonstruktor und die Klassenzeile wird von unnötigen Daten befreit. Jetzt müssen wir nur noch die Strings mit dem überladenen Operator + - in der richtigen Reihenfolge hinzufügen. Zeilen 50 - 53 und sehen, was passiert ist - Zeile 58.
Ergebnis des Programms:
1) In der Nähe von Lukomorye gibt es eine grüne Eiche;
2) Alles dreht sich in einer Kette im Kreis;
3) Tag und Nacht ist die Katze eine Wissenschaftlerin
4) Goldene Kette an der Eiche:
========================================
Vers, nachdem die Zeilen korrekt hinzugefügt wurden:
In der Nähe von Lukomorye gibt es eine grüne Eiche;
Goldene Kette an der Eiche:
Tag und Nacht ist die Katze eine Wissenschaftlerin
Alles dreht sich in einer Kette im Kreis;
========================================
a = 5
b = 5
c = 5 + 5 = 10
Grenzwerte für die Überlastung des Bedieners
. Punkt (Klassenelement auswählen);
* Sternchen (Definition oder Dereferenzierung eines Zeigers);
:: Doppelpunkt (Methodenumfang);
?: Fragezeichen mit Doppelpunkt (ternärer Vergleichsoperator);
# scharf (Präprozessorsymbol);
## Doppelkreuz (Präprozessorsymbol);
Größe von Operator zum Ermitteln der Größe eines Objekts in Bytes;
Vergessen Sie nicht, dass es beim Programmieren sehr wünschenswert ist, alles zu tun, um Ihren Code so klar wie möglich zu gestalten. Dieses Prinzip gilt für alles: die Namen, die Sie Variablen, Funktionen, Strukturen, Klassen geben, sowie die Aktionen, die ein überladener Operator ausführt. Versuchen Sie, diese Aktionen so nah wie möglich an der logischen Bedeutung der Operatoren zu definieren. Beispiel: + zum Hinzufügen von Zeichenfolgen oder anderen Klassenobjekten, - zum Löschen einer Zeichenfolge usw.
Es ist zu beachten, dass viele Programmierer eine negative Einstellung gegenüber der Überlastung von Operatoren haben. Die Möglichkeit einer Operatorüberlastung wird bereitgestellt, um das Verständnis und die Lesbarkeit des Programmcodes zu erleichtern. Gleichzeitig kann es im Gegenteil dazu führen, dass Ihr Programm komplizierter wird, und es wird für viele Programmierer schwierig sein, es zu verstehen. Denken Sie an die „goldene Mitte“ und verwenden Sie Überlastung nur dann, wenn sie Ihnen und anderen tatsächlich zugute kommt. Auf eine Überlastung des Bedieners kann durchaus verzichtet werden. Dies bedeutet jedoch nicht, dass Sie dieses Thema ignorieren können. Sie sollten es verstehen, und sei es nur, weil Sie eines Tages mit der Überlastung des Codes einer anderen Person zu kämpfen haben und leicht herausfinden können, was was ist.
Hier haben wir uns ganz kurz mit der Operatorüberladung in C++ vertraut gemacht. Wir haben sozusagen die Spitze des Eisbergs gesehen. Und Ihre Hausaufgabe (JA – HAUSAUFGABE!) wird darin bestehen, das Programm zu ändern, indem Sie eine Operatorüberladung hinzufügen, um eine Zeile zu löschen. Wählen Sie selbst aus, welchen Operator Sie überlasten möchten. Oder bieten Sie Ihre eigene Version des Code-Upgrades an und fügen Sie ihm das hinzu, was Sie für notwendig und interessant halten. Sie können Ihre „Werke“ in den Kommentaren zu diesem Artikel hinzufügen. Wir sind an Ihren Lösungen interessiert. Viel Glück!
Jede Wissenschaft verfügt über Standardnotationen, die das Verständnis von Ideen erleichtern. In der Mathematik sind dies beispielsweise Multiplikation, Division, Addition und andere symbolische Notationen. Der Ausdruck (x + y * z) ist viel einfacher zu verstehen als „y, c, z multiplizieren und zu x addieren“. Stellen Sie sich vor, bis zum 16. Jahrhundert gab es in der Mathematik keine symbolischen Notationen; alle Ausdrücke wurden verbal geschrieben, als wäre es ein literarischer Text mit einer Beschreibung. Und die uns bekannten Operationsbezeichnungen tauchten noch später auf. Die Bedeutung einer kurzen symbolischen Notation kann kaum überschätzt werden. Basierend auf solchen Überlegungen wurde den Programmiersprachen die Operatorüberladung hinzugefügt. Schauen wir uns ein Beispiel an.
Fast wie jede andere Sprache unterstützt C++ viele Operatoren, die mit im Sprachstandard integrierten Datentypen arbeiten. Die meisten Programme verwenden jedoch benutzerdefinierte Typen, um bestimmte Probleme zu lösen. Beispielsweise werden komplexe Mathematikaufgaben in einem Programm implementiert, indem komplexe Zahlen oder Matrizen als benutzerdefinierte C++-Typen dargestellt werden. Eingebaute Operatoren wissen nicht, wie sie ihre Arbeit verteilen und die erforderlichen Prozeduren für Benutzerklassen ausführen sollen, egal wie offensichtlich sie auch erscheinen mögen. Daher wird zum Beispiel für das Hinzufügen von Matrizen meist eine eigene Funktion erstellt. Offensichtlich ist der Aufruf von sum_matrix(A, B) im Code weniger klar als der Aufruf von A + B.
Betrachten wir eine Beispielklasse komplexer Zahlen:
//eine komplexe Zahl als Paar von Gleitkommazahlen darstellen. Klasse complex ( double re, im; public: complex (double r, double i) :re(r), im(i) () //Konstruktor komplexer Operator+(complex); //Additionsüberladung komplexer Operator*(complex); //Multiplikationsüberladung); void main() ( complex a( 1, 2 ), b( 3, 4 ), c(0, 0); c = a + b; c = a.operator+(b); ////Operatorfunktion kann sein Dieser Eintrag wird wie jede Funktion aufgerufen und entspricht a+b c = a*b + complex(1, 3); //Es werden die üblichen Regeln für die Priorität von Additions- und Multiplikationsoperationen befolgt)
Auf ähnliche Weise können Sie beispielsweise Ein-/Ausgabeoperatoren in C++ überladen und an die Darstellung komplexer Strukturen wie Matrizen anpassen.
Eine vollständige Liste aller Operatoren, für die der Überladungsmechanismus verwendet werden kann:
Wie Sie der Tabelle entnehmen können, ist eine Überladung für die meisten Sprachoperatoren akzeptabel. Eine Überlastung des Bedieners kann nicht erforderlich sein. Dies geschieht ausschließlich aus Bequemlichkeitsgründen. Daher gibt es beispielsweise in Java keine Operatorüberladung. Und nun zum nächsten wichtigen Punkt.
Der rechte Operand dieser Operatoren ist der Name, nicht der Wert. Daher könnte eine Überlastung dazu führen, dass viele mehrdeutige Konstrukte geschrieben werden, und würde das Leben von Programmierern erheblich erschweren. Obwohl es viele Programmiersprachen gibt, die eine Überladung aller Operatoren ermöglichen – zum Beispiel Überladung
Beschränkungen für Betreiberüberlastung:
Ein binärer Operator wird als Memberfunktion mit einer Variablen oder als Funktion mit zwei Variablen definiert. Für jeden binären Operator @ im Ausdruck a@b, @ gelten die folgenden Konstruktionen:
a.operator@(b) oder Operator@(a, b).
Betrachten wir am Beispiel der Klasse der komplexen Zahlen die Definition von Operationen als Klassenmitglieder und Hilfsoperationen.
Klasse complex ( double re, im; public: complex& Operator+=(Complex Z); Complex& Operator*=(Complex Z); ); //Hilfsfunktionen komplexer Operator+(komplex z1, komplex z2); komplexer Operator+(komplex z, doppelt a);
Welcher Operator gewählt wird und ob er überhaupt gewählt wird, wird durch die internen Mechanismen der Sprache bestimmt, auf die weiter unten eingegangen wird. Dies geschieht normalerweise durch Typvergleich.
Die Entscheidung, ob eine Funktion als Mitglied einer Klasse oder außerhalb einer Klasse beschrieben werden soll, ist im Allgemeinen Geschmackssache. Im obigen Beispiel war das Auswahlprinzip wie folgt: Wenn die Operation den linken Operanden ändert (z. B. a + = b), schreiben Sie ihn in die Klasse und verwenden Sie die Übergabe einer Variablen an die Adresse, um ihn direkt zu ändern. Wenn die Operation nichts ändert und einfach einen neuen Wert zurückgibt (z. B. a + b), verschieben Sie ihn aus dem Bereich der Klassendefinition.
Die Definition der Überladung unärer Operatoren in C++ erfolgt auf ähnliche Weise, mit dem Unterschied, dass sie in zwei Typen unterteilt werden:
Genau wie bei binären Operatoren wird die Auswahl durch die C++-Mechanismen getroffen, wenn die Operatordeklaration sowohl innerhalb als auch außerhalb der Klasse erfolgt.
Der binäre Operator @ soll auf Objekte x der Klasse X und y der Klasse Y angewendet werden. Die Regeln zum Auflösen von x@y lauten wie folgt:
Wurden in 1-4 mehrere Operator@-Deklarationen gefunden, erfolgt die Auswahl nach den Regeln zur Auflösung überladener Funktionen.
Die Suche nach Deklarationen unärer Operatoren erfolgt auf genau die gleiche Weise.
Lassen Sie uns nun die Klasse der komplexen Zahlen detaillierter konstruieren, um einige der zuvor genannten Regeln zu demonstrieren.
Klasse complex ( double re, im; public: complex& Operator+=(complex z) ( //funktioniert mit Ausdrücken wie z1 += z2 re += z.re; im += z.im; return *this; ) complex& Operator+= (double a) ( //funktioniert mit Ausdrücken wie z1 += 5; re += a; return *this; ) complex (): re(0), im(0) () //Konstruktor für die Standardinitialisierung. Also So , alle deklarierten komplexen Zahlen haben Anfangswerte (0, 0) komplex (doppeltes r): re(r), im(0) () // Der Konstruktor ermöglicht es, die Form komplex z = 11; äquivalent auszudrücken Notation z = complex( 11); complex (double r, double i): re(r), im(i) () //constructor ); komplexer Operator+(komplex z1, komplexer z2) ( //funktioniert mit Ausdrücken wie z1 + z2 komplexer res = z1; return res += z2; //unter Verwendung eines als Mitgliedsfunktion definierten Operators) komplexer Operator+(komplex z, doppeltes a) ( //verarbeitet Ausdrücke der Form z+2 complex res = z; return res += a; ) complex Operator+(double a, complex z) ( //verarbeitet Ausdrücke der Form 7+z complex res = z; return res += a; ) //…
Wie Sie dem Code entnehmen können, handelt es sich bei der Operatorüberladung um einen sehr komplexen Mechanismus, der stark wachsen kann. Dieser granulare Ansatz ermöglicht jedoch eine Überladung auch für sehr komplexe Datenstrukturen. Beispiel: Überladung eines C++-Operators in einer Vorlagenklasse.
Das Erstellen solcher Funktionen für alle kann mühsam und fehleranfällig sein. Wenn Sie beispielsweise einen dritten Typ zu den betrachteten Funktionen hinzufügen, müssen Sie Operationen berücksichtigen, die auf der Kombination der drei Typen basieren. Sie müssen 3 Funktionen mit einem Argument schreiben, 9 mit zwei und 27 mit drei. Daher kann in einigen Fällen die Implementierung all dieser Funktionen und eine erhebliche Reduzierung ihrer Anzahl durch den Einsatz der Typkonvertierung erreicht werden.
Der Indexierungsoperator „“ muss immer als Klassenmitglied definiert werden, da er das Verhalten eines Objekts auf ein Array reduziert. In diesem Fall kann das Indexargument einen beliebigen Typ haben, sodass Sie beispielsweise assoziative Arrays erstellen können.
Der Funktionsaufrufoperator „()“ kann als binäre Operation betrachtet werden. Beispielsweise ist in der Konstruktion „Ausdruck (Liste von Ausdrücken)“ der linke Operand der binären Operation () „Ausdruck“ und der rechte Operand eine Liste von Ausdrücken. Die Funktion „operator()()“ muss Mitglied der Klasse sein.
Der Sequenzoperator "," (Komma) wird für Objekte aufgerufen, wenn neben ihnen ein Komma steht. Der Operator ist jedoch nicht an der Auflistung der Funktionsargumente beteiligt.
Der Dereferenzierungsoperator „->“ muss ebenfalls als Mitglied der Funktion definiert werden. In seiner Bedeutung kann es als unärer Postfix-Operator definiert werden. Gleichzeitig muss es unbedingt entweder einen Link oder einen Zeiger zurückgeben, der den Zugriff auf das Objekt ermöglicht.
Aufgrund seiner Verknüpfung mit dem linken Operanden wird es auch nur als Mitglied einer Klasse definiert.
Die Zuweisungsoperatoren „=", Adressen „&" und Sequenzen „,“ müssen im öffentlichen Block definiert sein.
Das Überladen von Operatoren hilft bei der Implementierung eines der Schlüsselaspekte von OOP in Bezug auf Polymorphismus. Es ist jedoch wichtig zu verstehen, dass Überladung nichts anderes ist als eine andere Art, Funktionen aufzurufen. Das Ziel der Operatorüberladung besteht häufig eher darin, das Codeverständnis zu verbessern, als in der Verbesserung bestimmter Probleme.
Und das ist noch nicht alles. Sie sollten sich auch darüber im Klaren sein, dass die Überlastung von Bedienern ein komplexer Mechanismus mit vielen Fallstricken ist. Daher ist es sehr leicht, einen Fehler zu machen. Dies ist der Hauptgrund, warum die meisten Programmierer von der Operatorüberladung abraten und sie nur als letzten Ausweg und mit vollem Vertrauen in Ihre Aktionen verwenden.
Letzte Aktualisierung: 12.08.2018
Neben Methoden können wir auch Operatoren überladen. Nehmen wir zum Beispiel an, wir haben die folgende Counter-Klasse:
Klassenzähler (öffentlicher int-Wert (get; set;))
Diese Klasse stellt einen Zähler dar, dessen Wert in der Value-Eigenschaft gespeichert wird.
Nehmen wir an, wir haben zwei Objekte der Klasse Counter – zwei Zähler, die wir basierend auf ihrer Value-Eigenschaft vergleichen oder hinzufügen möchten, indem wir Standardvergleichs- und Additionsoperationen verwenden:
Zähler c1 = neuer Zähler (Wert = 23); Zähler c2 = neuer Zähler (Wert = 45); bool result = c1 > c2; Zähler c3 = c1 + c2;
Derzeit ist jedoch weder die Vergleichs- noch die Additionsoperation für Counter-Objekte verfügbar. Diese Operationen können für eine Reihe primitiver Typen verwendet werden. Beispielsweise können wir standardmäßig numerische Werte hinzufügen, aber der Compiler weiß nicht, wie er Objekte komplexer Typen – Klassen und Strukturen – hinzufügt. Und dafür müssen wir die benötigten Operatoren überlasten.
Das Überladen von Operatoren besteht darin, eine spezielle Methode in der Klasse zu definieren, für deren Objekte wir einen Operator definieren möchten:
Öffentlicher statischer Return_Type-Operator (Parameter) ()
Diese Methode muss über öffentliche statische Modifikatoren verfügen, da die Operatorüberladung für alle Objekte dieser Klasse verwendet wird. Als nächstes kommt der Name des Rückgabetyps. Der Rückgabetyp stellt den Typ dar, dessen Objekte wir empfangen möchten. Als Ergebnis des Hinzufügens von zwei Counter-Objekten erwarten wir beispielsweise, dass wir ein neues Counter-Objekt erhalten. Und als Ergebnis des Vergleichs der beiden möchten wir ein Objekt vom Typ bool erhalten, das angibt, ob der bedingte Ausdruck wahr oder falsch ist. Abhängig von der Aufgabe können die Rückgabetypen jedoch beliebig sein.
Dann gibt es anstelle des Namens der Methode den Schlüsselwortoperator und den Operator selbst. Und dann werden die Parameter in Klammern aufgeführt. Binäre Operatoren benötigen zwei Parameter, unäre Operatoren einen Parameter. Und in jedem Fall muss einer der Parameter den Typ darstellen – die Klasse oder Struktur, in der der Operator definiert ist.
Lassen Sie uns beispielsweise eine Reihe von Operatoren für die Counter-Klasse überladen:
Klassenzähler ( öffentlicher int Wert ( get; set; ) öffentlicher statischer Zähleroperator +(Zähler c1, Zähler c2) ( neuer Zähler zurückgeben ( Wert = c1.Wert + c2.Wert ); ) öffentlicher statischer Bool-Operator >(Zähler c1, Zähler c2) ( return c1.Value > c2.Value; ) öffentlicher statischer Bool-Operator<(Counter c1, Counter c2) { return c1.Value < c2.Value; } }
Da alle überladenen Operatoren binär sind, also auf zwei Objekte angewendet werden, gibt es für jede Überladung zwei Parameter.
Da wir bei der Additionsoperation zwei Objekte der Klasse Counter hinzufügen möchten, akzeptiert der Operator zwei Objekte dieser Klasse. Und da wir durch die Addition ein neues Counter-Objekt erhalten möchten, wird diese Klasse auch als Rückgabetyp verwendet. Alle Aktionen dieses Operators laufen auf die Erstellung eines neuen Objekts hinaus, dessen Value-Eigenschaft die Werte der Value-Eigenschaft beider Parameter kombiniert:
Öffentlicher statischer Zähleroperator +(Zähler c1, Zähler c2) ( neuen Zähler zurückgeben ( Wert = c1.Wert + c2.Wert ); )
Außerdem wurden zwei Vergleichsoperatoren neu definiert. Wenn wir einen dieser Vergleichsoperatoren überschreiben, müssen wir auch den zweiten dieser Operatoren überschreiben. Die Vergleichsoperatoren selbst vergleichen die Werte der Value-Eigenschaften und geben je nach Ergebnis des Vergleichs entweder true oder false zurück.
Jetzt verwenden wir überladene Operatoren im Programm:
Static void Main(string args) ( Counter c1 = new Counter ( Value = 23 ); Counter c2 = new Counter ( Value = 45 ); bool result = c1 > c2; Console.WriteLine(result); // false Counter c3 = c1 + c2; Console.WriteLine(c3.Value); // 23 + 45 = 68 Console.ReadKey(); )
Es ist erwähnenswert, dass wir diese Methode auch überladen können, d. h. eine andere Version dafür erstellen, da es sich bei der Operatordefinition im Wesentlichen um eine Methode handelt. Fügen wir beispielsweise der Counter-Klasse einen weiteren Operator hinzu:
Öffentlicher statischer int-Operator +(Counter c1, int val) ( return c1.Value + val; )
Diese Methode addiert den Wert der Value-Eigenschaft und eine bestimmte Zahl und gibt deren Summe zurück. Und wir können auch diesen Operator verwenden:
Zähler c1 = neuer Zähler (Wert = 23); int d = c1 + 27; // 50 Console.WriteLine(d);
Es ist zu berücksichtigen, dass sich beim Überladen die Objekte, die dem Operator über Parameter übergeben werden, nicht ändern dürfen. Beispielsweise können wir einen Inkrementoperator für die Counter-Klasse definieren:
Öffentlicher statischer Zähleroperator ++(Counter c1) ( c1.Value += 10; return c1; )
Da der Operator unär ist, benötigt er nur einen Parameter – ein Objekt der Klasse, in der der Operator definiert ist. Dies ist jedoch eine falsche Definition von Inkrement, da der Bediener die Werte seiner Parameter nicht ändern sollte.
Und eine korrektere Überladung des Inkrementoperators würde so aussehen:
Öffentlicher statischer Zähleroperator ++(Zähler c1) ( neuen Zähler zurückgeben ( Wert = c1.Wert + 10 ); )
Das heißt, es wird ein neues Objekt zurückgegeben, das einen erhöhten Wert in der Value-Eigenschaft enthält.
In diesem Fall müssen wir keine separaten Operatoren für die Präfix- und Postfix-Inkrementierung (sowie die Dekrementierung) definieren, da eine Implementierung in beiden Fällen funktioniert.
Zum Beispiel verwenden wir die Präfix-Inkrementierungsoperation:
Counter counter = new Counter() ( Value = 10 ); Console.WriteLine($"(counter.Value)"); // 10 Console.WriteLine($"((++counter).Value)"); // 20 Console.WriteLine($"(counter.Value)"); // 20
Konsolenausgabe:
Jetzt verwenden wir das Postfix-Inkrement:
Counter counter = new Counter() ( Value = 10 ); Console.WriteLine($"(counter.Value)"); // 10 Console.WriteLine($"((counter++).Value)"); // 10 Console.WriteLine($"(counter.Value)"); // 20
Konsolenausgabe:
Es ist auch erwähnenswert, dass wir die wahren und falschen Operatoren überschreiben können. Definieren wir sie beispielsweise in der Counter-Klasse:
Klassenzähler ( public int Value ( get; set; ) public static bool Operator true(Counter c1) ( return c1.Value != 0; ) public static bool Operator false(Counter c1) ( return c1.Value == 0; ) // der Rest des Klasseninhalts)
Diese Operatoren werden überladen, wenn wir ein Objekt eines Typs als Bedingung verwenden möchten. Zum Beispiel:
Counter counter = new Counter() ( Value = 0 ); if (Zähler) Console.WriteLine(true); sonst Console.WriteLine(false);
Beim Überladen von Operatoren müssen Sie berücksichtigen, dass nicht alle Operatoren überladen werden können. Insbesondere können wir die folgenden Operatoren überladen:
unäre Operatoren +, -, !, ~, ++, --
binäre Operatoren +, -, *, /, %
Vergleichsoperationen ==, !=,<, >, <=, >=
logische Operatoren &&, ||
Zuweisungsoperatoren +=, -=, *=, /=, %=
Und es gibt eine Reihe von Operatoren, die nicht überladen werden können, zum Beispiel der Gleichheitsoperator = oder der ternäre Operator?: sowie eine Reihe anderer.
Eine vollständige Liste der überladenen Operatoren finden Sie in der MSDN-Dokumentation
Beim Überladen von Operatoren müssen wir auch bedenken, dass wir die Priorität eines Operators oder seine Assoziativität nicht ändern können, wir können keinen neuen Operator erstellen oder die Logik von Operatoren in Typen ändern, die in .NET die Standardeinstellung sind.
In Verbindung stehende Artikel: | |
Erstellen einer Bootdiskette Partition Magic Das Programm parted magic ist nicht bootfähig
Parted Magic ist ein Programm für UNIX-Betriebssysteme, das entwickelt wurde... Die besten Programme zum Erstellen eines ISO-Disk-Images
Verwendung spezieller Programme. Ein virtuelles Abbild zu erstellen ist sehr... MacBook auf Werkseinstellungen zurücksetzen: Optionen und Anweisungen
Durch das Herunterfahren oder Neustarten Ihres Apple iMac wird der Inhalt des Speichers zurückgesetzt ... |