Operatori în C și C++

Versiunea actuală a paginii nu a fost încă examinată de colaboratori experimentați și poate diferi semnificativ de versiunea revizuită la 13 septembrie 2022; verificarea necesită 1 editare .

Limbajul de programare C++ acceptă toți operatorii progenitorului său, C, și este îmbunătățit cu noi operatori și caracteristici.

După evaluarea primului operand pentru operatorii nesupraîncărcați „ && , „ || ” și „ , ” (operatorul „virgulă”, ing.  virgulă ) compilatorul inserează un punct de secvență ( ing.  punct de secvență ), care garantează că toate efectele secundare (de exemplu, operatorul „postfix ++”) vor fi executate înainte ca al doilea operand să fie evaluat.

Limbajele cu sintaxă asemănătoare C (cum ar fi Java , C# , PHP și altele) împrumută adesea operatori C/C++, păstrându-le nu numai comportamentul, ci și precedența și asociativitatea .

Tabelele

Tabelele folosesc următoarea notație:

struct T { // sau operator de clasă float () const ; }; T :: operator float () const { /* implementare */ };
  • „Definiție în afara clasei”: definirea unui operator ca funcție; exemplu:
#include <iostream> struct T { // sau clasa /* ... */ }; std :: ostream & operator << ( std :: ostream & a , T const & b ) { /* implementare */ }
  • „N/A” : Nu este disponibil .

Operatori aritmetici

Operație (expresie) Operator Sintaxa expresiei Supraîncărcabil Implementat în C Exemplu
membru de tip T Definiție în afara clasei
Misiune = a = b da da R& T::operator =(S b); N / A
Plus + a + b da da R T::operator +(S b); R operator +(T a, S b);
Scădere - a - b da da R T::operator -(S b); R operator -(T a, S b);
plus unar + +a da da R T::operator +(); R operator +(T a);
minus unar - -a da da R T::operator -(); R operator -(T a);
Multiplicare * a * b da da R T::operator *(S b); R operator *(T a, S b);
Divizia / a / b da da R T::operator /(S b); R operator /(T a, S b);
Modulul de operare ( restul de la împărțirea numerelor întregi) [nota 1] % a % b da da R T::operator %(S b); R operator %(T a, S b);
Creştere prefix ++ ++a da da R& T::operator ++(); R& operator ++(T a);
sufix (postfix) ++ a++ da da R T::operator ++(int); R operator ++(T a, int);
[nota 2]
Decrementează prefix -- --a da da R& T::operator --(); R& operator --(T a);
sufix (postfix) -- a-- da da R T::operator --(int); R operator --(T a, int);
[nota 2]

Operatori de comparație

Operație (expresie) Operator Sintaxa expresiei Supraîncărcabil Implementat în C Exemplu
membru de tip T Definiție în afara clasei
Egalitatea == a == b da da R T::operator ==(S b); R operator ==(T a, S b);
Inegalitate != a != b da da R T::operator !=(S b); R operator !=(T a, S b);
Mai mult > a > b da da R T::operator >(S b); R operator >(T a, S b);
Mai puțin < a < b da da R T::operator <(S b); R operator <(T a, S b);
Mai mult sau egal >= a >= b da da R T::operator >=(S b); R operator >=(T a, S b);
Mai puțin sau egal <= a <= b da da R T::operator <=(S b); R operator <=(T a, S b);

Operatori logici

Operație (expresie) Operator Sintaxa expresiei Supraîncărcabil Implementat în C Exemplu
membru de tip T Definiție în afara clasei
Negație logică, NU ! !a da da R T::operator !(); R operator !(T a);
Înmulțirea booleană, ȘI && a && b da da R T::operator &&(S b); R operator &&(T a, S b);
Adăugarea logică, SAU || a || b da da R T::operator ||(S b); R operator ||(T a, S b);

Operatori pe biți

Operație (expresie) Operator Sintaxa expresiei Supraîncărcabil Implementat în C Exemplu
membru de tip T Definiție în afara clasei
inversare biți ~ ~a da da R T::operator ~(); R operator ~(T a);
ȘI pe biți & a & b da da R T::operator &(S b); R operator &(T a, S b);
SAU pe biți (sau) | a | b da da R T::operator |(S b); R operator |(T a, S b);
XOR pe biți (xor) ^ a ^ b da da R T::operator ^(S b); R operator ^(T a, S b);
Deplasare la stânga pe biți [nota 3] << a << b da da R T::operator <<(S b); R operator <<(T a, S b);
Deplasare biți la dreapta [nota 3] [nota 4] >> a >> b da da R T::operator >>(S b); R operator >>(T a, S b);

Atribuire compusă

Operație (expresie) Operator Sintaxa expresiei Sens Supraîncărcabil Implementat în C Exemplu
membru de tip T Definiție în afara clasei
Adăugarea combinată cu sarcina += a += b a = a + b da da R T::operator +=(S b); R operator +=(T a, S b);
Scăderea combinată cu atribuirea -= a -= b a = a - b da da R T::operator -=(S b); R operator -=(T a, S b);
Înmulțirea combinată cu atribuirea *= a *= b a = a * b da da R T::operator *=(S b); R operator *=(T a, S b);
Diviziunea combinată cu sarcina /= a /= b a = a / b da da R T::operator /=(S b); R operator /=(T a, S b);
Restul diviziunii combinat cu misiunea [nota 1] %= a %= b a = a % b da da R T::operator %=(S b); R operator %=(T a, S b);
„ȘI” pe biți combinat cu atribuirea &= a &= b a = a & b da da R T::operator &=(S b); R operator &=(T a, S b);
„SAU” pe biți (sau) combinat cu atribuirea |= a |= b a = a | b da da R T::operator |=(S b); R operator |=(T a, S b);
SAU exclusiv pe biți (xor) combinat cu alocare ^= a ^= b a = a ^ b da da R T::operator ^=(S b); R operator ^=(T a, S b);
Shift la stânga pe biți, combinat cu alocare <<= a <<= b a = a << b da da R T::operator <<=(S b); R operator <<=(T a, S b);
Deplasare la dreapta pe biți combinată cu atribuirea [nota 4] >>= a >>= b a = a >> b da da R T::operator >>=(S b); R operator >>=(T a, S b);

Operatori pentru lucrul cu pointeri și membrii clasei

Operator Sintaxă Supraîncărcabil Implementat în C Exemplu
membru de tip T Definiție în afara clasei
Accesarea unui element de matrice a[b] da da R T::operator [](S b);
N / A
Referire indirectă („obiectul indicat de o ”) *a da da R T::operator *(); R operator *(T a);
Link („adresa a ”) &a da da R T::operator &(); R operator &(T a);
Referirea unui membru al unei structuri („membru b al obiectului indicat de a ”) a->b da da R* T::operator ->();[nota 5]
N / A
Referirea unui membru al unei structuri („membru b al obiectului a ”) a.b Nu da N / A
Membrul indicat de b în obiectul indicat de a [nota 6] a->*b da Nu R T::operator ->*(S b); R operator ->*(T a, S b);
Membru indicat de b în obiectul a a.*b Nu Nu N / A

Alți operatori

Operator Sintaxă Supraîncărcabil Implementat în C Exemplu
membru de tip T Definiție în afara clasei
Functor a(a1, a2) da da R T::operator ()(S a1, U a2, ...); N / A
Operatorul virgulă a, b da da R T::operator ,(S b); R operator ,(T a, S b);
Operație condiționată ternară a ? b : c Nu da N / A
Operator de extensie a domeniului de aplicare a::b Nu Nu N / A
Litere personalizate (introduse în C++11) "a"_b da Nu N / A R operator "" _b(T a)
Dimensiunea (dimensiunea) sizeof(a)[nota 7]
sizeof(type)
Nu da N / A
Alinierea ( alinierea ) alignof(type)sau [nota 8]_Alignof(type) Nu da N / A
Introspecţie typeid(a)
typeid(type)
Nu Nu N / A
Tip turnare (type) a da da T::operator R(); N / A
[nota 9]
Alocare de memorie new type da Nu void* T::operator new(size_t x); void* operator new(size_t x);
Alocarea memoriei pentru o matrice new type[n] da Nu void* T::operator new[](size_t x); void* operator new[](size_t x);
Eliberarea memoriei delete a da Nu void T::operator delete(void* x); void operator delete(void* x);
Eliberarea memoriei ocupate de o matrice delete[] a da Nu void T::operator delete[](void* x); void operator delete[](void* x);

Note:

  1. 1 2 Operatorul % funcționează numai cu numere întregi. Pentru numerele cu virgulă mobilă, utilizați funcția () din fișierul " math.h " .fmod
  2. 1 2 Pentru a face distincția între operatorii de prefix și sufix (postfix), a fost adăugat un parametru de tip formal neutilizat la operatorii de postfix . Adesea, acestui parametru nu i se dă nici măcar un nume.int
  3. 1 2 În biblioteca iostream , operatorii „ ” și „ ” sunt utilizați pentru a lucra cu ieșirea și intrarea în flux.<<>>
  4. 1 2 Conform standardului C99, mutarea unui număr negativ la dreapta este un comportament definit de implementare (vezi comportament nespecificat ). Multe compilatoare , inclusiv gcc (vezi documentația Arhivată 22 septembrie 2019 la Wayback Machine  ) , implementează schimbarea aritmetică , dar standardul nu interzice implementarea deplasării logice .
  5. Tipul de returnare al operatorului " " trebuie să fie un tip căruia i se aplică operatorul " " , cum ar fi un pointer. Dacă " " este de tipul " ", iar clasa " " supraîncărcă operatorul " ", expresia " " este extinsă ca " ".operator->()->xCCoperator->()x->yx.operator->()->y
  6. Vezi un exemplu în articolul Wayback Machine Arhivat 17 mai 2013 „Implementarea unui operator Smart Pointer ” de Scott Myers de la Dr. Jurnalul lui Dobb , numărul din octombrie 1999. ->*
  7. Operatorul este de obicei scris cu paranteze. Dacă operandul este un nume de variabilă, parantezele sunt opționale. Dacă operandul este un nume de tip, sunt necesare parantezele.sizeof
  8. Standardul limbajului C++ definește alignof. Un operator similar în limbajul standard C se numește _Alignof.
  9. Pentru un operator de turnare, tipul de returnare nu este specificat în mod explicit, deoarece este același cu numele operatorului.

Prioritatea operatorului

Acest tabel listează prioritatea și asociativitatea operatorilor. Operatorii enumerați în tabelul de mai sus (înainte) au o prioritate mai mare (precedentă de evaluare). Când se ia în considerare o expresie, operatorii cu prioritate mai mare vor fi evaluați înaintea operatorilor cu prioritate mai mică. Dacă în aceeași celulă sunt specificați mai mulți operatori, atunci aceștia au aceeași prioritate și sunt evaluați în secvența specificată de asociativitate. Precedența operatorului nu se modifică atunci când sunt supraîncărcați.


Acest tabel de priorități este suficient în majoritatea cazurilor, cu următoarele excepții. Operatorul ternar „?:” poate conține un operator „virgulă” sau o atribuire în expresia din mijloc, dar compilatorul interpretează codul „ „ ca „ „, și nu ca o expresie fără sens „ „. Astfel, expresia dintre și este tratată ca și cum ar fi între paranteze. a ? b, c : da ? (b, c) : d(a ? b), (c : d)?:

O prioritate Operator Descriere Asociativitatea
unu

Cel mai inalt

:: Rezoluția domeniului Nu
2 ++ Creșterea sufixului De la stanga la dreapta
-- Decrementarea sufixului
() Apel de funcție
[] Preluarea unui element de matrice
. Selectarea unui element prin referință
-> Selectarea unui element prin indicator
typeid() RTTI (numai C++; vezi typeid )
const_cast Tip casting (C++) (vezi const cast )
dynamic_cast Tip casting (C++) (vezi dynamic cast )
reinterpret_cast Tastarea jocului de cuvinte (C++) (vezi reinterpret_cast )
static_cast Tip turnare (C++) (vezi casting static )
3 ++ increment de prefix De la dreapta la stânga
-- decrementarea prefixului
+ plus unar
- minus unar
! NU logic
~ Pe bit NU
(type) Tip turnare
* Dereferențierea pointerului
& Preluarea adresei obiectului
sizeof Dimensiunea (dimensiunea)
new,new[] Alocarea dinamică a memoriei (C++)
delete,delete[] Dealocarea memoriei dinamice (C++)
patru .* Pointer către membru (C++) De la stanga la dreapta
->* Pointer către membru (C++)
5 * Multiplicare
/ Divizia
% Obținerea restului unei diviziuni
6 + Plus
- Scădere
7 << Deplasare biți la stânga
>> Deplasare biți la dreapta
opt < Mai puțin
<= Mai puțin sau egal
> Mai mult
>= Mai mult sau egal
9 == Egalitatea
!= Inegalitate
zece & ȘI pe biți (și)
unsprezece ^ XOR pe biți (xor)
12 | SAU pe biți (sau)
13 && ȘI logic
paisprezece || SAU logic
cincisprezece ?: Operație condiționată ternară De la dreapta la stânga
= Misiune
+= Adăugarea combinată cu sarcina
-= Scăderea combinată cu atribuirea
*= Înmulțirea combinată cu atribuirea
/= Diviziunea combinată cu sarcina
%= Calculul restului unei diviziuni, combinat cu o atribuire
<<= Shift la stânga pe biți, combinat cu alocare
>>= Deplasare la dreapta pe biți, combinată cu alocare
&= „ȘI” pe biți combinat cu atribuirea
|= „SAU” pe biți combinat cu atribuirea
^= SAU exclusiv pe biți (xor) combinat cu alocare
throw Aruncare excepție operator (C++)
16 , Operatorul virgulă De la stanga la dreapta

Descriere

Compilatorul folosește un tabel de precedență pentru a determina ordinea în care operatorii sunt evaluați.

  • De exemplu, ++x*3ar fi ambiguu fără reguli de prioritate. Din tabel, putem spune că x este asociat mai întâi cu operatorul ++ , și abia apoi cu operatorul * , deci indiferent de acțiunea operatorului ++ , această acțiune este doar pe x (și nu pe x*3). Astfel, expresia este echivalentă cu ( ++x, x*3).
  • La fel și cu codul 3*x++în care tabelul afirmă că incrementul se aplică numai pentru x și nu pentru 3*x. Din punct de vedere funcțional, această expresie este echivalentă cu ( ) dacă exprimați variabila temporară ca tmp .tmp=x, x++, tmp=3*tmp, tmp

Legarea operatorului în standardele C și C++ este definită în termeni de gramatică a limbii, nu în termeni de tabel. Acest lucru poate crea conflicte. De exemplu, în C, sintaxa pentru o instrucțiune condiționată este:

expresie logică - SAU - ? expresie : conditional - expresie

Și în C++:

expresie logică - SAU - ? expresie : atribuire - expresie

Din acest motiv, expresia:

e = a < d? a++ : a = d

vor fi percepute diferit în cele două limbi. În C, expresia este incorectă din punct de vedere sintactic deoarece rezultatul unei instrucțiuni condiționale nu poate servi ca valoare l (adică partea stângă a unei instrucțiuni de atribuire).

În C++, expresia va fi analizată ca fiind validă: [1]

e = ( a < d ? a ++ : ( a = d ))

Precedența operatorilor logici pe biți este oarecum neintuitivă [2] . Din punct de vedere conceptual &, și |sunt aceiași operatori aritmetici ca *și +respectiv.

Expresia este tratată sintactic ca , dar expresia este echivalentă cu . Din acest motiv, este adesea necesar să folosiți paranteze pentru a specifica în mod explicit ordinea evaluării. a & b == 7a & (b == 7)a + b == 7(a + b) == 7

Sinonime de operator în C++

Standardul C++ definește [3] digrafe pentru unii operatori:

Digraf Șir echivalent
și &&
bitand &
and_eq &=
sau ||
bitor |
sau_echiv |=
xor ^
xor_eq ^=
nu !
nu_echiv !=
compl ~

Digrafele pot fi folosite în același mod ca și operatorii, sunt sinonime pentru operatori. De exemplu, digraful „ ” poate fi folosit pentru a înlocui operatorii „ȘI pe biți” și „obține adresa”, sau în definirea tipurilor de referință. Astfel, codul „ ” este echivalent cu codul „ ”. bitandint bitand ref = n;int & ref = n;

Standardul ANSI/ISO C definește digrafele enumerate ca constante #define(vezi preprocesor ). Constantele sunt definite în fișierul antet " iso646.h". Pentru compatibilitatea C, standardul C++ definește un fișier de antet inactiv " ciso646".

Note

  1. Operatorul ternar C/C++ are de fapt aceeași prioritate ca și operatorii de atribuire? . preaplin stiva. Preluat la 22 septembrie 2019. Arhivat din original la 6 august 2020.
  2. Chistory (link în jos) . Consultat la 11 ianuarie 2013. Arhivat din original pe 22 iunie 2013. 
  3. ISO/IEC JTC1/SC22/WG21 - Comitetul pentru standarde C++ . ISO/IEC 14882:1998(E)  Limbajul de programare C++ . - Grupul Internaţional pentru Standardizarea Limbului de Programare C++, 1998. - P. 40-41.

Link -uri