Oczywistym przykładem odpowiedniego przeciążenia operatora są dowolne klasy, które zachowują się tak samo, jak działają liczby. Tak więc klasy BigInt (jak sugeruje Jalayn ), liczby zespolone lub klasy macierzy (jak sugeruje Superbest ) wszystkie mają te same operacje, które zwykłe liczby tak dobrze odwzorowują na operatory matematyczne, podczas gdy operacje czasowe (jak sugeruje svick ) ładnie odwzorowują podzbiór tych operacji.
Nieco bardziej abstrakcyjnie, operatory mogą być używane podczas wykonywania operacji typu set , więc operator+
może być związkiem , operator-
może być uzupełnieniem itp. To jednak zaczyna rozciągać paradygmat, szczególnie jeśli używasz operatora dodawania lub mnożenia dla operacji, która nie jest t przemienny , jak można się spodziewać.
Sam C # ma doskonały przykład przeciążenia operatora nienumerycznego . Wykorzystuje +=
i -=
do dodawania i odejmowania delegatów , tj. Rejestrowania i wyrejestrowywania ich. Działa to dobrze, ponieważ operatory +=
i -=
działają tak, jak byś tego oczekiwał, a to skutkuje znacznie bardziej zwięzłym kodem.
Dla purysty jednym z problemów z +
operatorem łańcucha jest to, że nie jest on przemienny. "a"+"b"
to nie to samo co "b"+"a"
. Rozumiemy ten wyjątek dla ciągów, ponieważ jest tak powszechny, ale jak możemy stwierdzić, czy użycie operator+
na innych typach będzie przemienne, czy nie? Większość ludzi zakłada, że tak jest, chyba że obiekt jest podobny do łańcucha , ale tak naprawdę nigdy nie wiadomo, co ludzie przyjmą.
Podobnie jak w przypadku łańcuchów, wątki matryc są również dość dobrze znane. Oczywiste jest, że Matrix operator* (double, Matrix)
jest to mnożenie skalarne, podczas gdy na przykład Matrix operator* (Matrix, Matrix)
byłoby mnożeniem macierzowym (tj. Macierzą mnożenia iloczynu iloczynowego).
Podobnie użycie operatorów z delegatami jest tak bardzo dalekie od matematyki, że jest mało prawdopodobne, aby popełniono te błędy.
Nawiasem mówiąc, na konferencji ACCU w 2011 r. Roger Orr i Steve Love przedstawili sesję „ Niektóre przedmioty są bardziej równe niż inne” - spojrzenie na wiele znaczeń równości, wartości i tożsamości . Ich slajdy można pobrać , podobnie jak dodatek Richarda Harrisa o równości zmiennoprzecinkowej . Podsumowanie: Należy być bardzo ostrożnym z operator==
tu być smoki!
Przeciążenie operatora jest bardzo potężną techniką semantyczną, ale jest łatwe do nadmiernego użycia. Idealnie powinieneś go używać tylko w sytuacjach, gdy z kontekstu jasno wynika, jaki jest efekt przeciążenia operatora. Pod wieloma względami a.union(b)
jest jaśniejsze niż a+b
i a*b
jest o wiele bardziej niejasne niż a.cartesianProduct(b)
, zwłaszcza że wynik działania kartezjańskiego byłby SetLike<Tuple<T,T>>
raczej wynikiem niż SetLike<T>
.
Prawdziwe problemy z przeciążeniem operatora pojawiają się, gdy programista zakłada, że klasa będzie zachowywać się w jeden sposób, ale w rzeczywistości zachowuje się w inny sposób. Sugeruję, że tego rodzaju starcie semantyczne należy unikać.