6. Wyrażenia i operatory

6.2. Podział operatorów

Ogólnie operatory można podzielić na kilka grup:

Pierwszy, najbardziej ogólny z podziałów dotyczy liczby argumentów. W tym przypadku mamy do czynienia z operatorami jedno-, dwu-, i wieloargumentowymi. Jednak nie zawsze ten podział jest podziałem zrozumiałym w naturalny sposób. O ile nie budzi on naszego sprzeciwu w przypadku operatorów arytmetycznych (dodawanie dwuargumentowe, jednoargumentowy minus) czy logicznych (logiczna suma która ma dwa argumenty, czy negacja o jednym argumencie), o tyle nie bardzo wiadomo jak rozumieć pojęcie argumentu dla omawianego wcześniej operatora wyłuskania?

Dlatego też naszym zdaniem o wiele ważniejszy jest podział ze względu na rodzaj wykonywanej operacji. Z tego punktu widzenia możemy wydzielić następujące grupy operatorów.

Operatory arytmetyczne

Do operatorów arytmetycznych zaliczamy oprócz standardowego dodawania, odejmowania, mnożenia i dzielenia także operator modulo, inkrementacji i dekrementacji w dwóch wersjach, przed- i przyrostkowej, czy też … operator przypisania =. Wynikiem działania operatora przypisania jest wartość przypisana do l-wartości, po wykonaniu ew. konwersji typów. Typ wyniku zastosowania operatora arytmetycznego jest wynikiem niejawnej konwersji typów składowych operacji.

Operatory relacji

Operatory relacji służą, jak sama nazwa mówi – do ustalenia relacji w jakiej pozostają ze sobą argumenty. W tej grupie mamy dostęp do operatora równoważności (==), nierównoważności, większości, mniejszości i pochodnych. Znaczenie tych operatorów może być przedefiniowana przez programistę (i często bywa, w przeciwieństwie do pozostałych operatorów).

Mimo dużej liczby operatorów w C++ nie ma operatora tożsamości, znanego choćby z php. Jego brak nie jest dotkliwy ze względu na możliwość porównania wskaźników, o których wspominaliśmy, że jednoznacznie definiują nam tożsamość obiektu. Więc jeśli dwa wskaźniki są równoważne, to wskazywane obiekty są tożsame.

Wynikiem zastosowania operatora relacji jest zawsze wartość logiczna

Operatory logiczne

Operatory logiczne służą do budowania i wykonywania zdań logicznych. Mamy do dyspozycji operatory logicznej koniunkcji, agregacji i negacji. Wynikiem ich zastosowania jest zawsze wartość logiczna. Uważajcie, by operatorów logicznych nie mylić z następną grupą – operatorami bitowymi.

W ramach umożliwienia lepszej optymalizacji programów i skrócenia czasu wykonania, standard zakłada pewne dodatkowe zasady co do operatorów && i || (i tylko dla tych). Wymienione operatory są wyjątkowe w tym sensie, że mają zdefiniowaną kolejność wartościowania wyrażeń (wykonania) i nie zawsze drugie wyrażenie musi zostać obliczone. Zawsze obliczane (wartościowane) są wyrażenia kolejno od lewej do prawej, i w przypadku gdy wartość całego zdania logicznego można ustalić, nie ma potrzeby obliczania pozostałych wyrażeń, więc nie jest to wykonywane. Wyobraźmy sobie że w wyrażeniu < w1 > || < w2 >, < w1 > jest prawdą. W takim przypadku niezależnie od tego, jakie byłoby < w2 >, wynik operacji jest już znany – też jest prawdą. Podobnie dzieje się przy operatorze &&.
Pozostałe operatory niczego takiego nie zakładają - w wyrażeniu < w1 > + < w2 > może być najpierw obliczone < w1 > a potem < w2 >, ale równie dobrze może być odwrotnie (tu kompilator może sobie zdecydować, jak mu bardziej pasuje).

Operatory bitowe

Operatory bitowe również wykonują operacje logiczne, lecz nie na całych zmiennych, tylko na pojedynczych bitach wchodzących w skład zmiennych czy stałych. Na pojedynczych bitach – nie znaczy że bezpośrednio można wykonać operacje na wybranych bitach, są one wykonywane na wszystkich bitach danej zmiennej, lecz na każdym z nich niezależnie. Tutaj oprócz typowych koniunkcji, agregacji i negacji mamy dostęp również do różnicy symetrycznej XOR czy przesunięcia bitowego w lewo i w prawo. Typ wyniku po zastosowaniu operatora bitowego jest zależny od typu argumentów.

Operatory łączone

W C++ występuje duża grupa operatorów które są połączeniem przypisania wraz z jakąś operacją. Zawsze działają one wg następującego schematu:


// zapis klasyczny
x = x+y;
// zapis skrócony
x += y;

W przypadku tych operatorów L-wartość jest jednocześnie jednym z argumentów wyrażenia. Operatory łączone są dla wszystkich operatorów arytmetycznych i bitowych.

Inne operatory

Trochę dziwna nazwa dla grupy, prawda? Lecz w C++ występuje kilka operatorów, które wyjątkowo ciężko sklasyfikować. Mamy wśród nich wspomniane operatory zasięgu, wyłuskania, ale też i operator pobrania rozmiaru zmiennej czy typu sizeof, operator przecinka zwracający zawsze wartość najbardziej po prawej stronie (ten operator może łączyć wiele argumentów), czy specjalną postać wyrażenia warunkowego (wyrażenie ? wartość_prawda : wartość_fałsz).