Während ich C # lernte, stellte ich fest, dass das C # das Überladen von Operatoren unterstützt. Ich habe ein Problem mit einem guten Beispiel, welches:
- Sinnvoll (zB Hinzufügen der Klasse "Schaf und Kuh")
- Ist kein Beispiel für die Verkettung von zwei Zeichenfolgen
Beispiele aus der Basisklassenbibliothek sind willkommen.
==
, eine Multiplikation durchzuführen, ist dies für mich sinnvoll, für andere jedoch möglicherweise nicht ! Ist diese Frage zur Legitimität welcher Facility-Programmiersprachen oder handelt es sich um "Coding Best Practices"?Antworten:
Die offensichtlichen Beispiele für eine angemessene Überladung von Operatoren sind Klassen, die sich genauso verhalten wie Zahlen. So BigInt Klassen (wie Jalayn schon sagt), komplexe Zahlen oder Matrix - Klassen (wie Superbest schon sagt) alle die gleichen Operationen haben , dass gewöhnliche Zahlen so wirklich gut auf mathematischen Operatoren Karte haben, während der Zeit - Operationen (wie vorgeschlagen svick ) schön auf eine Teilmenge der Karte dieser Operationen.
Etwas abstrakter könnten Operatoren verwendet werden, wenn set-ähnliche Operationen ausgeführt werden, also
operator+
eine Vereinigung ,operator-
eine Ergänzung usw. Dies erweitert jedoch das Paradigma, insbesondere wenn Sie den Additions- oder Multiplikationsoperator für eine Operation verwenden, die nicht ' t kommutativ , wie Sie vielleicht erwarten.C # selbst bietet ein hervorragendes Beispiel für das Überladen nicht numerischer Operatoren. Es verwendet
+=
und-=
, um Delegierte hinzuzufügen und zu subtrahieren , dh sie zu registrieren und die Registrierung aufzuheben. Dies funktioniert gut, da die Operatoren+=
und so-=
funktionieren, wie Sie es erwarten würden, und dies führt zu wesentlich präziserem Code.Für den Puristen ist eines der Probleme mit dem String-
+
Operator, dass er nicht kommutativ ist."a"+"b"
ist nicht dasselbe wie"b"+"a"
. Wir verstehen diese Ausnahme für Strings, weil sie so häufig vorkommt, aber wie können wir feststellen, ob die Verwendungoperator+
für andere Typen kommutativ ist oder nicht? Die meisten Menschen gehen davon aus, dass dies der Fall ist, es sei denn, das Objekt ist stringartig , aber Sie wissen nie wirklich, was die Menschen davon ausgehen.Wie bei Saiten sind auch bei Matrizen die Schwächen bekannt. Es ist offensichtlich, dass
Matrix operator* (double, Matrix)
es sich um eine Skalarmultiplikation handelt, wohingegenMatrix operator* (Matrix, Matrix)
es sich beispielsweise um eine Matrixmultiplikation (dh eine Matrix aus Skalarmultiplikationen) handeln würde .In ähnlicher Weise ist die Verwendung von Operatoren mit Delegierten so weit von der Mathematik entfernt, dass Sie diese Fehler wahrscheinlich nicht machen werden.
Im Übrigen an der 2011 ACCU Konferenz , Roger Orr & Steve Liebe präsentiert eine Sitzung auf einige Objekte als andere gleich sind - ein Blick auf die vielen Bedeutungen der Gleichheit, der Wert und Identität . Ihre Folien können heruntergeladen werden , ebenso wie der Anhang von Richard Harris zur Gleitkomma-Gleichheit . Fazit: Sei sehr vorsichtig mit
operator==
, hier seid Drachen!Das Überladen von Operatoren ist eine sehr leistungsfähige semantische Technik, die jedoch leicht zu überbeanspruchen ist. Idealerweise sollten Sie es nur in Situationen verwenden, in denen aus dem Kontext klar hervorgeht, wie sich ein überladener Operator auswirkt. In vielerlei Hinsicht
a.union(b)
ist klarer alsa+b
, unda*b
ist viel dunkler alsa.cartesianProduct(b)
, zumal das Ergebnis eines kartesischen ProduktesSetLike<Tuple<T,T>>
eher ein a als ein a wäreSetLike<T>
.Die wirklichen Probleme beim Überladen von Operatoren treten auf, wenn ein Programmierer davon ausgeht, dass sich eine Klasse auf die eine oder andere Weise verhält. Ich schlage vor, dass diese Art von semantischem Konflikt vermieden werden sollte.
quelle
d1 + d2
zwei beliebige Delegaten desselben Typs angeben.Ich bin überrascht, dass niemand einen der interessanteren Fälle in BCL erwähnt hat:
DateTime
undTimeSpan
. Du kannst:TimeSpan
s, um eine andere zu erhaltenTimeSpan
TimeSpan
um ein negiertes zu erhaltenTimeSpan
DateTime
s, um a zu erhaltenTimeSpan
TimeSpan
von aDateTime
, um ein anderes zu erhaltenDateTime
Ein weiterer Satz von Operatoren , die Sinne auf eine Menge von Typen machen könnte
<
,>
,<=
,>=
. In der BCLVersion
implementiert sie zum Beispiel .quelle
Das erste Beispiel, das mir in den Sinn kommt, ist die Implementierung von BigInteger , mit der Sie mit großen Ganzzahlen mit Vorzeichen arbeiten können. Überprüfen Sie den MSDN-Link, um festzustellen, wie viele Operatoren überlastet wurden (das heißt, es gibt eine große Liste, und ich habe nicht überprüft, ob alle Operatoren überlastet wurden, aber es scheint so).
Da ich auch Java verwende und Java das Überladen von Operatoren nicht zulässt, ist das Schreiben unglaublich süßer
Dann in Java:
quelle
Ich bin froh, dass ich das gesehen habe, weil ich mit Irony rumgespielt habe und es eine GROSSARTIGE Verwendung von Operatorüberladung hat. Hier ist ein Beispiel dafür, was es tun kann.
Irony ist also ein ".NET Language Implementation Kit" und ein Parser-Generator (der einen LALR-Parser generiert). Anstatt eine neue Syntax / Sprache wie Parser-Generatoren wie yacc / lex lernen zu müssen, schreiben Sie die Grammatik in C # mit der Operatorüberladung. Hier ist eine einfache BNF-Grammatik
Es ist also eine einfache kleine Grammatik (entschuldigen Sie bitte, wenn es Unstimmigkeiten gibt, da ich nur BNF lerne und Grammatiken konstruiere). Schauen wir uns nun das C # an:
Wie Sie sehen, wird beim Überladen des Operators beim Schreiben der Grammatik in C # fast genau die Grammatik in BNF geschrieben. Für mich macht das nicht nur Sinn, sondern ist auch eine hervorragende Möglichkeit, den Operator zu überladen.
quelle
Das Schlüsselbeispiel ist operator == / operator! =.
Wenn Sie zwei Objekte einfach anhand von Datenwerten anstatt anhand von Verweisen vergleichen möchten, müssen Sie .Equals (und .GetHashCode!) Überladen und möglicherweise auch die Operatoren! = Und == verwenden, um die Konsistenz zu gewährleisten.
Ich habe noch nie wilde Überladungen anderer Operatoren in C # gesehen (ich stelle mir vor, dass es Edge-Fälle gibt, in denen dies nützlich sein könnte).
quelle
Dieses Beispiel von MSDN zeigt, wie komplexe Zahlen implementiert werden und der normale Operator + verwendet wird.
Ein weiteres Beispiel zeigt, wie es für das Hinzufügen einer Matrix gemacht wird, und erklärt, wie es nicht verwendet wird, um ein Auto zu einer Garage hinzuzufügen (lesen Sie den Link).
quelle
Guter Gebrauch von Überlastung kann selten sein, aber es kommt vor.
Das Überladen von operator == und operator! = zeigt zwei Denkrichtungen: Die, die es sagen, machen die Sache einfacher, und die, die dagegen sprechen, verhindern das Vergleichen von Adressen (dh, ich zeige auf die exakt gleiche Stelle im Speicher, nicht nur auf eine Kopie derselben) Objekt).
Überladungen von Cast-Operatoren halte ich in bestimmten Situationen für nützlich. Zum Beispiel musste ich einen Booleschen Wert, der als 0 oder 1 dargestellt wird, in XML serialisieren / deserialisieren. Der richtige (implizite oder explizite, ich vergesse) Umsetzungsoperator von Boolesch nach int und zurück hat den Trick gemacht.
quelle
object.ReferenceEquals()
.==
durch Casting zu erzwingen :(object)foo == (object)bar
Vergleicht immer Referenzen. Aber ich würde es vorziehenReferenceEquals()
, als @ dan04 erwähnt, weil es klarer ist, was es tut.Sie gehören nicht zu den Dingen, an die die Leute normalerweise denken, wenn sie Operatoren überladen, aber ich denke, einer der wichtigsten Operatoren, um überladen zu können, ist der Conversion-Operator .
Konvertierungsoperatoren sind besonders nützlich für Werttypen, die einen numerischen Typ "entzuckern" oder in einigen Kontexten wie ein numerischer Typ wirken können. Zum Beispiel könnten Sie einen speziellen definieren
Id
Typen, der eine bestimmte Kennung darstellt, und man konnte eine bieten implizite Konvertierung ,int
so dass Sie eine passieren könnenId
ein Verfahren , das eines nimmtint
, sondern eine explict Umwandlung vonint
zuId
so kann niemand einen Passint
in eine Methode, die ein dauert,Id
ohne es zuerst zu werfen.Als Beispiel außerhalb von C # enthält die Python-Sprache viele spezielle Verhaltensweisen, die als überladbare Operatoren implementiert sind. Dazu gehören der
in
Operator zum Testen der Zugehörigkeit, der()
Operator zum Aufrufen eines Objekts als ob es eine Funktion wäre und der Operator zum Testen der Zugehörigkeitlen
Operator zum Bestimmen der Länge oder Größe eines Objekts.Und dann haben Sie Sprachen wie Haskell, Scala und viele andere funktionale Sprachen, in denen Namen wie
+
nur normale Funktionen und überhaupt keine Operatoren sind (und es gibt Sprachunterstützung für die Verwendung von Funktionen in Infix-Position).quelle
Die Punktstruktur im System.Drawing- Namespace verwendet die Überladung, um zwei verschiedene Positionen mithilfe der Operatorüberladung zu vergleichen.
Wie Sie sehen, ist es mit der Überladung viel einfacher, die X- und Y-Koordinaten zweier Positionen zu vergleichen.
quelle
Wenn Sie mit dem mathematischen Vektor vertraut sind, wird der
+
Operator möglicherweise überladen . Sie könnten einen Vektora=[1,3]
mit hinzufügenb=[2,-1]
und erhaltenc=[3,2]
.Das Überladen von equals (==) kann ebenfalls nützlich sein (auch wenn es wahrscheinlich besser ist, eine
equals()
Methode zu implementieren ). So setzen Sie die Vektorbeispiele fort:quelle
Stellen Sie sich einen Code zum Zeichnen in einem Formular vor
Ein weiteres bekanntes Beispiel ist die Verwendung einer Struktur zum Speichern von Positionsinformationen in Form eines Vektors.
Nur zur späteren Verwendung als
quelle
operator+
sollte nicht überlastet werden (ein Punkt in Bezug auf einen Vektor implementieren können, aber man sollte hinzufügen zwei Punkte nicht in der Lage sein)p1+((p2-p1)+(p3-p1)+(p4-p1))/4
, aber das scheint etwas umständlich.