Operatory w C i C++

To jest lista operatorów w językach programowania C i C++ . Wszystkie wymienione operatory istnieją w C++; kolumna „Zawarte w C” określa, czy operator jest również obecny w C. Zauważ, że C nie obsługuje przeciążania operatorów .

Gdy nie jest przeciążony, dla operatorów && , || , i , ( operator przecinka ), po obliczeniu pierwszego operandu znajduje się punkt sekwencji .

C++ zawiera również operatory konwersji typów const_cast , static_cast , dynamic_cast i reinterpret_cast . Formatowanie tych operatorów oznacza, że ​​ich poziom pierwszeństwa jest nieistotny.

Większość operatorów dostępnych w C i C++ jest również dostępna w innych językach z rodziny C, takich jak C# , D , Java , Perl i PHP z tym samym pierwszeństwem, asocjatywnością i semantyką.

Tabela

Na potrzeby tych tabel a , b i c reprezentują prawidłowe wartości (literały, wartości ze zmiennych lub wartość zwracaną), odpowiednio nazwy obiektów lub lwartości. R , S i T oznaczają dowolne typy, a K typ klasy lub typ wyliczeniowy.

Operatory arytmetyczne

Wszystkie operatory arytmetyczne istnieją w C i C++ i mogą być przeciążane w C++.

Imię operatora Składnia Przykłady prototypów C++
Jako członek k Definicje klas zewnętrznych
Dodatek a + b R K :: operator + ( S b ); operator R + ( Ka , Sb ) ; _
Odejmowanie a - b R K :: operator - ( S b ); R operator - ( Ka , S b ) ;
Jednoargumentowy plus ( promocja liczb całkowitych ) + za R K :: operator + (); operator R + ( Ka ) ;
Jednoargumentowy minus ( dodatek odwrotny ) - _ R K :: operator - (); operator R - ( Ka ) ;
Mnożenie a * b R K :: operator * ( S b ); operator R * ( Ka , S b ) ;
Dział a / b R K :: operator / ( S b ); R operator / ( Ka , S b ) ;
Modulo (reszta całkowita) % b _ R K :: operator % ( S b ); operator R % ( Ka , Sb ) ; _
Przyrost Prefiks ++ za R & K :: operator ++ (); R & operator ++ ( K & a );
Przyrostek ++ _ R K :: operator ++ ( int ); Operator R ++ ( K & a , int );
Uwaga: C++ używa nienazwanego parametru fikcyjnego int do rozróżniania operatorów inkrementacji prefiksu i postfiksu.
Zmniejszenie Prefiks -- _ R & K :: operator -- (); R & operator -- ( K & a );
Przyrostek a -- R K :: operator -- ( int ); Operator R -- ( K & a , int );
Uwaga: C++ używa nienazwanego parametru dummy-parametru int do rozróżniania operatorów dekrementacji prefiksów i postfiksów.

Operatory porównania/operatory relacji

Wszystkie operatory porównania mogą być przeciążane w C++.

Imię operatora Składnia
Zawarte w C
Przykłady prototypów
Jako członek k Definicje klas zewnętrznych
Równy za == b Tak bool K :: operator == ( S const & b ) const ; operator bool == ( K const & a , S const & b );
Nie równe
a != b a not_eq b
Tak bool K :: operator != ( S const & b ) const ; operator bool != ( K const & a , S const & b );
Lepszy niż a > b Tak bool K :: operator > ( S const & b ) const ; operator bool > ( K const & a , S const & b );
Mniej niż a < b Tak bool K :: operator < ( S const & b ) const ; operator bool < ( K const & a , S const & b );
Większe bądź równe a >= b Tak bool K :: operator >= ( S const & b ) const ; operator bool >= ( K const & a , S const & b );
Mniejszy lub równy a <= b Tak bool K :: operator <= ( S const & b ) const ; operator bool <= ( K const & a , S const & b );
Porównanie trójstronne a <=> b NIE auto K :: operator <=> ( const S & b ); operator auto <=> ( const K & a , const S & b );
Operator ma w sumie 3 możliwe zwracane typy: std::weak_ordering , std::strong_ordering i std::partial_ordering, na które wszystkie są konwertowalne.

Operatory logiczne

Wszystkie operatory logiczne istnieją w C i C++ i mogą być przeciążane w C++, chociaż odradza się przeciążanie logicznego AND i logicznego OR, ponieważ jako przeciążone operatory zachowują się jak zwykłe wywołania funkcji, co oznacza, że ​​obliczane są oba ich operandy , więc tracą swoją dobrze używaną i oczekiwaną właściwość oceny zwarcia .

Imię operatora Składnia Przykłady prototypów C++
Jako członek k Definicje klas zewnętrznych
Negacja logiczna (NIE)
! a nie a
bool K :: operator ! (); operator logiczny ! ( Ka ) ;
Logiczne I
a && b a i b
bool K :: operator && ( S b ); operator logiczny && ( K a , S b );
Logiczne LUB

|| _ b a ??!?! b a lub b
bool K :: operator || ( S b ); operator logiczny || ( Ka , Sb ) ; _

Operatory bitowe

Wszystkie operatory bitowe istnieją w C i C++ i mogą być przeciążane w C++.

Imię operatora Składnia Przykłady prototypów
Jako członek k Definicje klas zewnętrznych
Bitowo NIE

~ a ?? kompl a -
R K :: operator ~ (); operator R ~ ( Ka ) ;
Bitowe ORAZ
a & b a biti b
R K :: operator & ( S b ); R operator & ( Ka , Sb ) ; _
Bitowe LUB

| _ b a ??! b bitor b _
R K :: operator | ( S b ); operator R | ( Ka , Sb ) ; _
Bitowe XOR

a ^ b a ??' b a xor b
R K :: operator ^ ( S b ); R operator ^ ( Ka , S b ) ;
Bitowe przesunięcie w lewo a << b R K :: operator << ( S b ); Operator R << ( Ka , S b ) ;
Bitowe przesunięcie w prawo a >> b R K :: operator >> ( S b ); Operator R >> ( Ka , S b ) ;

Operatory przypisania

Wszystkie wyrażenia przypisania istnieją w C i C++ i mogą być przeciążane w C++.

Dla podanych operatorów semantyka wbudowanego złożonego wyrażenia przypisania a ⊚= b jest równoważna a = a ⊚ b , z wyjątkiem tego, że a jest oceniane tylko raz.

Imię operatora Składnia Przykłady prototypów C++
Jako członek k Definicje klas zewnętrznych
Bezpośrednie zadanie za = b R & K :: operator = ( S b );
Przypisanie dodatku a += b R & K :: operator += ( S b ); R & operator += ( K & a , S b );
Zadanie odejmowania a -= b R & K :: operator -= ( S b ); R & operator -= ( K & a , S b );
Zadanie mnożenia * = b R & K :: operator *= ( S b ); R & operator *= ( K & a , S b );
Przydział dywizji a /= b R & K :: operator /= ( S b ); R & operator /= ( K & a , S b );
Przypisanie modulo % = b R & K :: operator %= ( S b ); R & operator %= ( K & a , S b );
Przypisanie bitowe AND
a &= b a and_eq b
R & K :: operator &= ( S b ); R & operator &= ( K & a , S b );
Bitowe przypisanie LUB

a |= b a ??!= b a or_eq b
R & K :: operator |= ( S b ); R & operator |= ( K & a , S b );
Bitowe przypisanie XOR

a ^= b a ??'= b a xor_eq b
R & K :: operator ^= ( S b ); R & operator ^= ( K & a , S b );
Bitowe przypisanie przesunięcia w lewo a <<= b R & K :: operator <<= ( S b ); R & operator <<= ( K & a , S b );
Przypisanie bitowego przesunięcia w prawo a >>= b R & K :: operator >>= ( S b ); R & operator >>= ( K & a , S b );

Operatory składowe i wskaźnikowe

Imię operatora Składnia Może przeciążać w C++
Zawarte w C
Przykłady prototypów C++
Jako członek k Definicje klas zewnętrznych
Indeks

a [ b ] a <: b :> a ??( b ??)
Tak Tak R & K :: operator []( S b );
Pośredni („obiekt wskazany przez a ”) * _ Tak Tak R & K :: operator * (); R & operator * ( Ka ) ;
Adres-z ("adres a ")
& bit i a
Tak Tak R * K :: operator & (); R * operator & ( Ka ) ;
Wyłuskanie struktury („element b obiektu wskazywany przez a ”) a -> b Tak Tak R * K :: operator -> ();
Odniesienie do struktury („człon b obiektu a ”) za . B NIE Tak
Członek wybrany przez wskaźnik do elementu członkowskiego b obiektu wskazywanego przez a a ->* b Tak NIE R & K :: operator ->* ( S b ); R & operator - >* ( Ka , S b );
Członek obiektu a wybrany przez wskaźnik do członka b za .* b NIE NIE

Inni operatorzy

Imię operatora Składnia Może przeciążać w C++
Zawarte w C
Przykłady prototypów
Jako członek k Definicje klas zewnętrznych

Wywołanie funkcji Zobacz Obiekt funkcji .
za ( a1, a2 ) Tak Tak R K::operator ()( Sa , T b , ...) ;
Przecinek a , b Tak Tak R K :: operator ,( S b ); R operator ,( Ka , S b ) ;
Warunek trójskładnikowy a ? b : c NIE Tak
Rozdzielczość zakresu a :: b NIE NIE

Literały zdefiniowane przez użytkownika od C++ 11
"a"_b Tak NIE Operator R "" _b ( T a )
Rozmiar
rozmiarrozmiar _ _ ( typ )
NIE Tak

Rozmiar pakietu parametrów od C++11
rozmiar... (argumenty) NIE NIE

Wyrównanie od C++ 11

alignof ( typ ) lub _Alignof ( typ )
NIE Tak
Identyfikacja typu
typeid (a) typeid ( typ )
NIE NIE
Konwersja (obsada w stylu C) ( typ )a Tak Tak K :: operator R ();
Konwersja typ (a) NIE NIE Uwaga: zachowuje się jak const_cast/static_cast/reinterpret_cast
konwersja static_cast static_cast < typ > (a) Tak NIE
K :: operator R (); jawne K :: operator R (); od C++11
Uwaga: w przypadku konwersji zdefiniowanych przez użytkownika zwracany typ jest niejawnie i koniecznie zgodny z nazwą operatora.
dynamiczna konwersja rzutowania dynamic_cast < typ > (a) NIE NIE
konwersja const_cast const_cast < typ >(a) NIE NIE
konwersja reinterpret_cast reinterpret_cast < typ >(a) NIE NIE
Przydziel pamięć nowy typ Tak NIE void * K :: operator new ( size_t x ); void * operator nowy ( rozmiar_t x );
Przydziel pamięć (tablica)

nowy typ [ n ] nowy typ <: n :> nowy typ ??( n ??)
Tak NIE void * K :: operator new []( size_t a ); void * operator new []( size_t a );
Zwolnij przydział pamięci usunąć _ Tak NIE void K :: operator delete ( void * a ); pusty operator usuń ( pusty * a );
Zwolnij przydział pamięci (tablica)

usuń[] usuń <::> usuń ??(??) a
Tak NIE void K :: operator delete []( void * a ); operator void usuń []( void * a );

Sprawdzanie wyjątków od C++ 11
nie z wyjątkiem (a) NIE NIE

Uwagi:

Priorytet operatora

Poniżej znajduje się tabela przedstawiająca pierwszeństwo i łączność wszystkich operatorów w językach C i C++ . Operatory są wymienione od góry do dołu, w porządku malejącym. Pierwszeństwo malejące odnosi się do priorytetu grupowania operatorów i operandów. Biorąc pod uwagę wyrażenie, operator wymieniony w jakimś wierszu zostanie zgrupowany przed operatorem wymienionym w wierszu poniżej. Operatory znajdujące się w tej samej komórce (w komórce może znajdować się kilka rzędów operatorów) są grupowane z takim samym priorytetem, w podanym kierunku. Przeciążenie nie ma wpływu na pierwszeństwo operatora.

Składnia wyrażeń w C i C++ jest określona przez gramatykę struktury fraz . Podana tutaj tabela została wywnioskowana z gramatyki. [ Potrzebne źródło ] W przypadku normy ISO C 1999, sekcja 6.5.6 uwaga 71 stwierdza, że ​​gramatyka C dostarczona przez specyfikację definiuje pierwszeństwo operatorów C, a także stwierdza, że ​​pierwszeństwo operatorów wynikające z gramatyki jest ściśle zgodne z sekcją specyfikacji zamawianie:

Składnia [C] [tj. gramatyka] określa pierwszeństwo operatorów w ocenie wyrażenia, które jest takie samo jak kolejność głównych podrozdziałów tego podrozdziału, najwyższy priorytet jako pierwszy”.

Tabela pierwszeństwa, choć w większości wystarczająca, nie może rozwiązać kilku szczegółów. W szczególności zauważ, że operator trójskładnikowy dopuszcza dowolne dowolne wyrażenie jako środkowy operand, mimo że jest wymieniony jako mający wyższy priorytet niż operatory przypisania i przecinka. w ten sposób ? b, c : d jest interpretowane jako ? (b, c) : d , a nie jako bezsensowne (a ? b), (c : d) . Tak więc wyrażenie w środku operatora warunkowego (pomiędzy ? a : ) jest analizowany tak, jakby był ujęty w nawiasy. Należy również zauważyć, że natychmiastowy, nieujęty w nawiasy wynik wyrażenia rzutowania C nie może być operandem sizeof . W związku z tym sizeof (int) * x jest interpretowane jako (sizeof(int)) * x , a nie sizeof ((int) * x) .

Precedens Operator Opis Asocjatywność
1

najwyższy

:: Rozdzielczość zakresu (tylko C++) Nic
2 ++ Przyrost przyrostka Od lewej do prawej
-- Dekrementacja postfiksowa
() Wywołanie funkcji
[] Indeksowanie tablicy
. Wybór elementu przez odniesienie
-> Wybór elementu za pomocą wskaźnika
typid() Informacje o typie czasu wykonywania (tylko C++) (zobacz typeid )
const_cast Rzutowanie typu (tylko C++) (zobacz const_cast )
dynamic_cast Rzutowanie typu (tylko C++) (zobacz rzutowanie dynamiczne )
reinterpret_cast Rzutowanie typów (tylko C++) (zobacz reinterpret_cast )
static_cast Rzutowanie typów (tylko C++) (zobacz static_cast )
3 ++ Przyrost prefiksu Od prawej do lewej
-- Zmniejszenie przedrostka
+ Jednoargumentowy plus
- Jednoargumentowy minus
! Logiczne NIE
~ Bitowe NIE (dopełnienie jedności)
( typ ) Wpisz obsadę
* Pośrednia (dereferencja)
& Adres
rozmiar Rozmiar
_Wyrównaj Wymóg wyrównania (od C11)
nowy , nowy[] Dynamiczna alokacja pamięci (tylko C++)
usunąć , usunąć[] Dynamiczne zwalnianie pamięci (tylko C++)
4 .* Wskaźnik do członka (tylko C++) Od lewej do prawej
->* Wskaźnik do członka (tylko C++)
5 * Mnożenie Od lewej do prawej
/ Dział
% Modulo (reszta)
6 + Dodatek Od lewej do prawej
- Odejmowanie
7 < Bitowe przesunięcie w lewo Od lewej do prawej
>> Bitowe przesunięcie w prawo
8 <=> Porównanie trójstronne (wprowadzone w C++20 — tylko w C++) Od lewej do prawej
9 < Mniej niż Od lewej do prawej
<= Mniejszy lub równy
> Lepszy niż
>= Większe bądź równe
10 == Równy Od lewej do prawej
!= Nie równe
11 & Bitowe ORAZ Od lewej do prawej
12 ^ Bitowe XOR (wyłączne lub) Od lewej do prawej
13 | Bitowe LUB (włączając lub) Od lewej do prawej
14 && Logiczne I Od lewej do prawej
15 || Logiczne LUB Od lewej do prawej
16 współ_oczekiwanie Przetwarzanie współprogramowe (tylko C++) Od prawej do lewej
współ_zysk
17 ?: Trójskładnikowy operator warunkowy Od prawej do lewej
= Bezpośrednie zadanie
+= Przydział według sumy
-= Przydział według różnicy
*= Przypisanie według produktu
/= Przypisanie przez iloraz
%= Przypisanie przez resztę
<<= Przypisanie przez bitowe przesunięcie w lewo
>>= Przypisanie przez bitowe przesunięcie w prawo
&= Przypisanie przez bitowe AND
^= Przypisanie przez bitowe XOR
|= Przypisanie przez bitowe OR
rzucić Operator Throw (zgłaszanie wyjątków, tylko C++)
18

najniższy

, Przecinek Od lewej do prawej

Notatki

Tabela pierwszeństwa określa kolejność wiązania w wyrażeniach łańcuchowych, gdy nie jest to wyraźnie określone w nawiasach.

  • Na przykład ++x*3 jest niejednoznaczne bez pewnych reguł pierwszeństwa. Tabela pierwszeństwa mówi nam, że: x jest ściślej „powiązany” z ++ niż z * , więc cokolwiek robi ++ (teraz lub później — patrz poniżej), robi to TYLKO z x (a nie z x*3 ) ; jest równoważne z ( ++x , x*3 ).
  • Podobnie z 3*x++ , gdzie chociaż post-fix ++ ma działać PO obliczeniu całego wyrażenia, tabela pierwszeństwa wyjaśnia, że ​​TYLKO x jest zwiększane (a NIE 3*x ). W rzeczywistości wyrażenie ( tmp=x++ , 3*tmp ) jest oceniane przy czym tmp jest wartością tymczasową. Jest to funkcjonalnie równoważne z czymś takim jak ( tmp=3*x , ++x , tmp ).
Pierwszeństwo i wiązania
  • Abstrahując od kwestii pierwszeństwa lub wiązania, rozważmy powyższy diagram dla wyrażenia 3+2*y[i]++. Zadaniem kompilatora jest przekształcenie diagramu w wyrażenie, w którym kilka operatorów jednoargumentowych (nazwijmy je 3+( . ), 2*( . ), ( . )++ i ( . )[ i ]) rywalizuje o powiązanie do y. Kolejność tabeli pierwszeństwa rozstrzyga końcowe wyrażenie podrzędne, na którym każde z nich działa: ( . )[ i ] działa tylko na y, ( . )++ działa tylko na y[i], 2*( . ) działa tylko na y[ i]++ i 3+( . ) działają „tylko” na 2*((y[i])++). Ważne jest, aby zauważyć, że CO podwyrażenie jest wykonywane przez każdy operator, jest jasne z tabeli pierwszeństwa, ale KIEDY każdy operator działa, nie jest rozstrzygane przez tabelę pierwszeństwa; w tym przykładzie operator ( . )++ działa tylko na y[i] zgodnie z regułami pierwszeństwa, ale same poziomy powiązania nie wskazują czasu postfiksu ++ (operator ( . )++ działa tylko po y [i ] jest oceniany w wyrażeniu).

Wielu operatorom zawierającym sekwencje wieloznakowe nadano „nazwy” zbudowane z nazwy operatora każdego znaku. Na przykład += i -= są często nazywane plus equal(s) i minus equal(s) , zamiast bardziej szczegółowych „przypisanie przez dodanie” i „przypisanie przez odjęcie”. Wiązanie operatorów w C i C++ jest określone (w odpowiednich standardach) przez faktoryzowaną gramatykę języka, a nie przez tabelę pierwszeństwa. Powoduje to pewne subtelne konflikty. Na przykład w języku C składnia wyrażenia warunkowego wygląda następująco:

     wyrażenie  logiczne  LUB  ?  wyrażenie  :  warunkowe  -  wyrażenie 

podczas gdy w C++ jest to:

     wyrażenie  logiczne  LUB  ?  wyrażenie  :  przypisanie  -  wyrażenie 

Stąd wyrażenie:

mi = za < re? a++ : a = d

jest analizowany inaczej w obu językach. W C to wyrażenie jest błędem składniowym, ponieważ składnia wyrażenia przypisania w C jest następująca:

   jednoargumentowe  -  wyrażenie  '='  przypisanie  -  wyrażenie 

W C++ jest analizowany jako:

           mi  =  (  za  <  re  ?  za  ++  :  (  za  =  re  )) 

co jest poprawnym wyrażeniem.

Jeśli chcesz użyć przecinka jako operatora w pojedynczym argumencie funkcji, przypisaniu zmiennej lub innej liście oddzielonej przecinkami, musisz użyć nawiasów okrągłych, np.:

              int  a  =  1  ,  b  =  2  ,  dziwnazmienna  =  (  ++  a  ,  b  ),  d  =  4  ; 

Krytyka pierwszeństwa operatorów bitowych i równościowych

Krytykowano pierwszeństwo bitowych operatorów logicznych. Koncepcyjnie, & i | to operatory arytmetyczne, takie jak * i +.

Wyrażenie a & b == 7 jest składniowo analizowane jako a & ( b == 7 ) , podczas gdy wyrażenie a + b == 7 jest analizowane jako ( a + b ) == 7 . Wymaga to częstszego używania nawiasów niż w innym przypadku.

Historycznie rzecz biorąc, nie było rozróżnienia składniowego między operatorami bitowymi i logicznymi. W BCPL , B i wczesnym C operatory && || nie istniał. Zamiast & | miały różne znaczenie w zależności od tego, czy są używane w „kontekście wartości logicznej” (tj. gdy oczekiwano wartości logicznej, na przykład w if ( a == b & c ) {...} zachowywał się jak operator logiczny, ale w c = a & b zachowywał się jak bitowy). Został zachowany, aby zachować kompatybilność wsteczną z istniejącymi instalacjami.

Co więcej, w C++ (i późniejszych wersjach C) operacje równości, z wyjątkiem operatora porównania trójstronnego, dają wartości typu bool , które są koncepcyjnie pojedynczym bitem (1 lub 0) i jako takie nie należą odpowiednio do „bitowego "operacje.

Synonimy operatora C++

C++ definiuje pewne słowa kluczowe, które działają jako aliasy dla wielu operatorów:

Słowo kluczowe Operator
I &&
i_równ &=
bitand &
bitor |
komplet ~
nie !
nie_równ !=
Lub ||
or_równ |=
xor ^
xor_eq ^=

Można ich używać dokładnie w taki sam sposób, jak symbole interpunkcyjne, które zastępują, ponieważ nie są tym samym operatorem pod inną nazwą, ale raczej prostymi zamiennikami nazwy (ciągu znaków) odpowiedniego operatora. Oznacza to, że wyrażenia (a > 0 i not flag) oraz (a > 0 && !flag) mają identyczne znaczenie. Oznacza to również, że na przykład bitand może być użyte do zastąpienia nie tylko operatora bitowego-i , ale także adresu-of operatora, a nawet można go użyć do określenia typów referencyjnych (np. int biti ref = n ). Specyfikacja ISO C uwzględnia te słowa kluczowe jako makra preprocesora w pliku nagłówkowym iso646.h . Aby zapewnić kompatybilność z C, C++ udostępnia nagłówek ciso646 , którego włączenie nie ma żadnego efektu.

Zobacz też

Linki zewnętrzne