W każdej nauce istnieją standardowe zapisy, które ułatwiają zrozumienie pomysłów. Na przykład w matematyce jest to mnożenie, dzielenie, dodawanie i inna symboliczna notacja. Wyrażenie (x + y * z) jest dużo łatwiejsze do zrozumienia niż "pomnóż y, z i dodaj do x". Wyobraźmy sobie, że aż do XVI wieku matematyka nie miała symbolicznej notacji, wszystkie wyrażenia były napisane werbalnie, jak gdyby był tekstem artystycznym z opisem. A zwykłe znaki operacji dla nas pojawiły się później. Trudno przecenić znaczenie krótkiego zapisu postaci. Na podstawie tych rozważań języki programowania zostały dodane do przeciążenia operatorów. Rozważ przykład.
Przykład przeciążenia operatora
//wyobraź sobie liczbę zespoloną w postaci pary liczb zpunkt przestawny.
klasa złożona {{12} double re, im;
public:
complex (double r, double i): re (r), im (i) {} //constructor
complex operator + (complex); //złożony operator zespołu przeciążającego
* (złożony); //przeciążenie mnożenia
};
void kompleks główny () {
a {1 2}, b {3}}, c {0}};
c = a + b;
c = a.operator + (b); ////funkcję operatora można nazwać dowolną funkcją, ten wpis jest równoważny z kompleksem a + b
c = a * b + (1 3); //przeprowadzono zwykłe zasady działania priorytetowych dodawania i mnożenia
}
W podobny sposób można zrobić, na przykład przeciążenia operatora /wy w C ++ i dostosować je do wyświetlania takich złożonych struktur jako szablony.
Operatorzy dostępni do przeciążenia
Pełny wykaz wszystkich operatorów, w przypadku których można zastosować mechanizm przeciążenia:
, 110nowość+ , | - , | * , | / | % | ^ | & amp; |
~ | ! | = | & lt; /p & gt; | & gt; | + = | |
- = , | = , | /= , | % = , | ^ = , | i wzmacniacz = , | | = |
= , | = , | == | ! = | |||
> = | i; | || , | ++ , | - , | - & gt; * | , |
- & gt; | nowy [] | usunąć | usunąć [] |
Jak wynika z tabeli, dla większości operatorów językowych dopuszczalne jest przeciążenie. Nie ma potrzeby przeciążania operatora. Odbywa się to wyłącznie dla wygody. Dlatego nie ma na przykład przeciążenia operatorów w Javie. A teraz o tak ważnym momencie.
Operatorzy, których przeciążenie jest zabronione
- Pozwolenie na widoczność - «::»;
- Wybór członka to ".";
- Wybór członka przez wskaźnik do członka - ". *";
- Trójskładnikowy operator warunkowy - «?:»;
- rozmiar operatora;
- Operator typu.
Prawym operandem danych operatorów jest nazwa, a nie wartość. Dlatego zezwolenie na ich przeciążenie mogłoby doprowadzić do napisania wielu niejednoznacznych projektów i znacznie skomplikowałoby życie programistów. Chociaż istnieje wiele języków programowania, które pozwalają na przeciążenie wszystkich operatorów - na przykład przeciążenie operatorów Pythona.
& lt; script type = "text /javascript" & gt;
var blockSettings2 = {blockID "R-A-70350-2" renderTo "yandex_rtb_R-A-70350-2" asynchroniczny :! 0};
, jeżeli (document.cookie.indexOf ("abmatch =") i GT = 0) {
blockSettings2 = {blockID "RA 70350-2" renderTo „yandex_rtb_R A-70350- 2 ", statId: 70350async:! 0};
}
! Zastosowanie (a, b, c, d, e) {A [c] = a [c] || [] do [C] .Push (funkcja () {Ya .Context.AdvManager.render (blockSettings2)}), e = b.getElementsByTagName ("scenariusz")d = b.createElement ("scenariusz") d.type = "text /JavaScript" d.src = "//an.yandex.ru/system/context.js",d.async=!0e.parentNode.insertBefore(d,e)}(this,this.document,"yandexContextAsyncCallbacks");
ograniczenia operator
ograniczenia przeciążenia
- nie może zostać zmieniona na jednoargumentowego operator binarny i odwrotnie, jak nie można dodać trzeci argument.
- Nie można tworzyć nowych operatorów innych niż te, które są. To ograniczeniepromuje eliminację wielu niejednoznaczności. Jeśli istnieje potrzeba nowego operatora, można użyć funkcji, która wykona pożądaną akcję dla tych celów.
- Funkcja operatora może być członkiem klasy lub mieć przynajmniej jeden argument typu. Wyjątkiem są operatorzy new i delete. Ta reguła zabrania zmiany znaczenia wyrażeń, jeśli nie zawierają typów obiektów zdefiniowanych przez użytkownika. W szczególności nie można utworzyć funkcji operatora, która działałaby tylko ze wskaźnikami lub zmuszała operatora dodawania do pracy jako mnożenie. Wyjątkiem są operatory "=", "& amp;" i "," dla obiektów klasy.
- Funkcja operatora z pierwszym terminem, należącym do jednego z wbudowanych typów danych w języku C ++, nie może być członkiem klasy.
- Nazwa dowolnej funkcji operatora rozpoczyna się od słowa kluczowego operator, po którym następuje symboliczne oznaczenie samego operatora.
- Wbudowane operatory są zdefiniowane w taki sposób, że istnieje między nimi połączenie. Na przykład następujące operatory są równoważne sobie: ++ x; x + = 1; x = x + 1. Po ponownym zdefiniowaniu, połączenie między nimi nie zostanie zachowane. Utrzymanie ich wspólnej pracy w podobny sposób z nowymi typami programistów będzie musiało dbać o siebie.
- Kompilator nie może myśleć. Wyrażenia z + 5 i 5 + z (gdzie z - liczba zespolona) będą rozpatrywane przez kompilator na różne sposoby. Pierwsza to "liczba zespolona +", a druga to "liczba + kompleks". Dlatego dla każdego wyrażenia musisz zdefiniować własną instrukcję dodawania.
- Podczas wyszukiwania definicji operatora kompilator nie nadaje preferencji żadnym członkom funkcji klasy ani funkcjom pomocniczym,które są zdefiniowane poza klasą. Dla kompilatora są równe.
Interpretacje operatorów binarnych i jednoarkowych.
Operator binarny jest zdefiniowany jako funkcja składowa z jedną zmienną lub jako funkcja z dwiema zmiennymi. Dla każdego operatora z binarnym ekspresji @ @ B @ tylko struktur:
Związek pośredni skryptu typu = "text /JavaScript" & gt;
var blockSettings3 = {blockID "R-A-70350-3" renderTo "yandex_rtb_R-A-70350-3" asynchroniczny :! 0};
, jeżeli (document.cookie.indexOf ("abmatch =") i GT = 0) {
blockSettings3 = {blockID "RA 70350-3" renderTo „yandex_rtb_R A-70350- 3 ", statId: 70350async:! 0};
}
! Zastosowanie (a, b, c, d, e) {A [c] = a [c] || [] do [C] .Push (funkcja () {Ya .Context.AdvManager.render (blockSettings3)}), e = b.getElementsByTagName ("scenariusz")d = b.createElement ("scenariusz") d.type = "text /JavaScript" d.src = "//an.yandex.ru/system/context.js",d.async=!0e.parentNode.insertBefore(d,e)}(this,this.document,"yandexContextAsyncCallbacks");
a.operator @ (b) lub operator @ (a, b).
Rozważmy przykład klasy liczb zespolonych dla definicji operacji jako członków klasy i pomocniczych.
klasa złożona {{174} double re, im;
public:
complex & amp; operator + = (complex z);
kompleks i amp; operator * = (złożony z);
};
//funkcji pomocnika
operatora + kompleks (kompleks złożony Z1 Z2);
operator złożony + (złożony z, podwójny a);
,
, który jest wybrany operatorów oraz wybiera się na ogół określane przez wewnętrzne mechanizmy języka, które zostaną omówione poniżej. Zazwyczaj dzieje się to zgodnie z typami.
Wybór opisać funkcję członka klasy lub poza tym - jest na ogół, smaku. W powyższym przykładzie, zasada doboru się w sposób następujący: jeżeli operacja zmiany lewy argument (na przykład, a + = B), po czym rejestruje się w klasie i w użyciu zmiennej transmisji, na swoich bezpośrednich zmian; jeśli operacja niemodyfikuje i po prostu zwraca nową wartość (na przykład a + b) - poza definicją klasy.
Definicja przeciążenia operatorów jednoargumentowych w C ++ występuje w taki sam sposób, z tą różnicą, że dzieli się je na dwa typy:
- operator prefiksu, zlokalizowany na operandzie, - @a, na przykład, i ++. o Zdefiniowany jako a.operator @ () lub operator @ (aa);
- operator przyrostowy, umieszczony za operandem, - b @, na przykład, i ++. o Zdefiniowane jako b.operator @ (int) lub operator @ (b, int)
W ten sam sposób, co w przypadku operatorów binarnych, w przypadku, gdy instrukcja operatora znajduje się zarówno w klasie, jak i poza nią, wybór zostanie dokonany za pomocą mechanizmów C ++.
Zasady wyboru operatora
Niech operator binarny @ zostanie zastosowany do obiektów x klasy X i y klasy Y. Reguły dla rozdzielczości x @ y będą następujące:
- jeśli X jest klasą, przejrzyj w niej definicję operatora @ jako termin X lub podstawową klasę X;
- , aby zobaczyć kontekst, w którym znajduje się wyrażenie x @ y;
- jeśli X należy do przestrzeni nazw N, poszukaj instrukcji operatora N;
- Jeśli Y należy do przestrzeni nazw M, poszukaj instrukcji operatora M.
Jeśli znaleziono kilka stwierdzeń operatora operatora @ w 1-4, wybór zostanie dokonany zgodnie z regułami zezwolenia na przeciążone funkcje.
Poszukiwanie operatorów jednoargumentowych odbywa się dokładnie w ten sam sposób.
Uściślij definicję kompleksu klasowego
Teraz skonstruujemy klasę liczb zespolonych w bardziej szczegółowy sposóbwykazać liczbę wcześniej ogłoszonych zasad.
klasa złożona {
double re, im;
publiczny:
złożony & amp; operator + = (complex z) {//działa z wyrażeniami w postaci z1 + = z2
re + = z.re;
im + = z.im;
zwracają * to;
}
complex & amp; operator + = (double a) {//działa z wyrażeniami w postaci z1 + = 5;
re + = a;
zwraca * to;
}
complex (): re , im
{} //konstruktor domyślnie inicjalizujący. W ten sposób, wszystkie liczbami zespolonymi ogłoszone będą miały wartości początkowej (0 0)
, kompleks (podwójne R): Re (R), IM
{} //konstruktor umożliwiają ekspresję formy złożonej z = 11; odpowiednik rekordu z = complex
;
kompleksu (R dwukrotnie dwukrotnie I) Re (R), IM (I) {} //konstruktor
};
operatora + kompleks (kompleks złożony z1 z2) {//współpracuje z wyrażenia Z1 + Z2
złożone res = z1;
return res + = z2; //operator określa się jako funkcję członu
}
operatora + kompleks (kompleks z, dwukrotnie a) {//wyrażenia uchwyt z + 2
złożone Res = Z;
return res + = a;
}
złożone operatora + (podwójne A, złożone z) {//wyrażenia uchwyt z + 7
złożone Res = Z;
return res + = a;
}
//
, jak pokazano na kodzie przeciążenia operatora jest dość skomplikowany mechanizm, który może rosnąć silnie. Jednak takie szczegółowe podejście pozwala na przeciążenie nawet w przypadku bardzo złożonych struktur danych. Na przykład przeciążanie operatorów C ++ w klasie szablonu. Takie tworzenie funkcji dla wszystkich i wszystkich może być uciążliwe i prowadzić do błędów. Na przykład, jeśli dodasz trzeci typ rozważanych funkcji, będziesz musiał rozważyć operacje z powodu kombinacji trzech typów. Będziemy musieli napisać 3 funkcje z jednym argumentem, 9 - z dwoma i 27 - z trzema. Dlatego w niektórych przypadkach wdrożenie wszystkich tych funkcji i znaczne ich zmniejszenieilości można osiągnąć, stosując konwersję typów.
;
kompleksu (R dwukrotnie dwukrotnie I) Re (R), IM (I) {} //konstruktor
};
operatora + kompleks (kompleks złożony z1 z2) {//współpracuje z wyrażenia Z1 + Z2
złożone res = z1;
return res + = z2; //operator określa się jako funkcję członu
}
operatora + kompleks (kompleks z, dwukrotnie a) {//wyrażenia uchwyt z + 2
złożone Res = Z;
return res + = a;
}
złożone operatora + (podwójne A, złożone z) {//wyrażenia uchwyt z + 7
złożone Res = Z;
return res + = a;
}
//