Operátorok (C++)

A Wikipédiából, a szabad enciklopédiából

A legtöbb programozási nyelv tartalmaz operátorokat, ezek speciális függvények, precedenciával, sokszor speciális(infix, postfix) jelölésmóddal, valamint a hagyományos függvényforma nélkül. A C++ átvette a C összes operátorát, valamint bevezetett újakat is, valamint néhánynak a szemantikáját is megváltoztatta.

Az operátorokat csoportosíthatjuk létrehozásuk célja szerint, így vannak aritmetikai, összehasonlító, bitszintű és egyéb operátorok.

Operátorok fordítása[szerkesztés]

A C++ fordítóban minden operátort hagyományos függvényalakra hoz a fordításkor előtt, így például az a+b alakból a.operator+(b) vagy operator+(a,b) lesz, attól függően, hogy tag vagy globális függvényként van deklarálva.

Az operátorok másik speciális tulajdonsága a precedenciájuk valamint az (bal vagy jobb) asszociativitásuk, ez határozza meg a kifejezések kiértékelési sorrendjét valamint az implicit zárójelezés irányát.

Specialitások[szerkesztés]

Konverziós operátorok[szerkesztés]

A C++ a hagyományos (type)arg alakú, C-stílusú konverzión túl alkalmaz három, ennél speciálisabb konverziós operátort, amivel egyértelműbbé tehetjük, hogy mit szeretnénk, és a fordító szólhat, ha az nem lehetséges, valamint hosszuk következtében kiugranak a kódból, könnyebbé téve a konverziók megtalálását, amelyek a pointerek után elsőszámú hibaforrásnak tekinthetők.

Alakjuk: operátornév<új-típus>(objektum);

static_cast[szerkesztés]

Konverzió egymásba konvertálható típusok között, fordítási hibát okoz, ha nem konvertálható oda-vissza a két típus.

reinterpret_cast[szerkesztés]

Erős átalakítás, gyakorlatilag tetszőleges típusok közötti átalakítást enged, veszélyes, kerülendő.

dynamic_cast[szerkesztés]

Pointerek és referenciák közötti futásidejű átalakítás, amely downcastra használható, azaz bázispointerből származtatott osztályra mutatót ad vissza. A konverzió mutatók esetén nullpointerrel tér vissza, referenciáknál (egyéb opciók híján) bad_cast kivételt dob, ha nem lehetséges az átalakítás, azaz a mutatott objektum típusa nem az elvárt.

const_cast[szerkesztés]

A konverzió leveszi a const vagy a volatile jelzőt egy változóról, szintén veszélyes lehet.

Tagként deklarált operátorok[szerkesztés]

A C++ lehetővé teszi konstruktorszerű szintaxissal konverziós operátorok használatát felhasználói típusoknál is.

Ekkor minden adott típust kívánó környezetben a normális konverziós szabályok szerint képesek konvertálódni. Az egyparaméterű (nem-explicit) konstruktorok és ezek az operátorok könnyen többértelműséget okozhatnak, mivel mindkettő képes implicit konverzióként viselkedni.

struct A
{
  operator int()
  { return 4; }
};

struct B
{
  operator A()
  { return A(); }
};

int main()
{
  int aint = A();  //aint értéke ekkor 4
  A b = B();       //B() konvertálódik A-vá
  int bint = b;    //bint is négy
}

Operátorok túlterhelése[szerkesztés]

A közönséges függvényekhez hasonlóan a legtöbb operátort is túl lehet terhelni, amely a felhasználói típusok kényelmesebb használatát teszi lehetővé(jellemző például az <<(eltoló) operátor túlterhelése, melyet a kimeneti folyamok használnak kimenetként). Értékadó(=, += stb.), &(címe) operátort csak tagfüggvényként lehet megírni, minden mást érdemesebb globálisként deklarálni, ha lehet(ha nem kell hozzáférniük a tagokhoz).

struct Complex
{
 //Barátfüggvény deklarációja, hogy hozzáférjen a tagokhoz
 friend std::ostream& operator<<(std::ostream& stream, const Complex& z);

 //Konstruktor, taginicializációs listával
 Complex(double a, double b): re(a), im(b) { }

 Complex& operator+=(const Complex& rhs)         //hozzáadó operátor tagfüggvény...
 {re += rhs.re; im += rhs.im; return *this;}
 private:
  double re, im;
};

Complex operator+(const Complex& lhs, const Complex& rhs)  //összeadó operátor viszont globális
{return Complex(lhs) += rhs;}

//az ostream definíciójához nem férünk hozzá, de
//operator<<(ostream&, const complex&)-t definiálhatunk
std::ostream& operator<<(std::ostream& stream, const Complex& z)
{
 return (stream << '(' << z.re << ", " << z.im << ')');
}

//Ezután az operátort egyszerűen használhatjuk:
Complex c(1.0, 4.6);
std::cout << c; //A kimeneten megjelenik: (1.0, 4.6)

Összefoglaló táblázat[szerkesztés]

Precedencia Operátor Rövid leírás Asszociativitás Jelölés Csak C++-ban Túlterhelhető
1 :: Hatókör-feloldás nincs a::b, ::b Igen Nem
2 ()
[]
->
.
++
--
Csoportosítás
Tömb-elérés
Mutatón keresztüli tag-elérés
Objektumon keresztüli tag-elérés
Posztfix növelés
Posztfix csökkentés
Bal (a)
a[]
ptr->b()
a.b()
a++
a--
Nem Nem
Igen
Igen
Nem
Igen
Igen
3 !
~
++
--
-
+
*
&
(típus)
sizeof
Logikai tagadás
Bitenkénti negálás
Prefix növelés
Prefix csökkentés
Előjel -
Előjel +
Dereferálás
Objektum címe
Konverzió típusra
Méret
Jobb !a
~a
++a
--a
-a
+a
*ptr
&a
(b)a
sizeof(a)
Nem Igen
Igen
Igen
Igen
Igen
Igen
Igen
Igen
Igen
Nem
4 ->*
.*
Tagkiválasztás mutatón/objektumon Bal a->*b()
a.*b()
Igen Igen
Nem
5 *
/
 %
Szorzás
Osztás
Maradékszámítás
Bal Infix Nem Igen
6 +
-
Összeadás
Kivonás
Bal Infix Nem Igen
7 <<
>>
Bitenkénti eltolás balra
Bitenkénti eltolás jobbra
Bal Infix Nem Igen
8 <
<=
>
>=
Kisebb
Kisebb-egyenlő
Nagyobb
Nagyobb-egyenlő
Bal Infix Nem Igen
9 ==
 !=
Egyenlő
Nemegyenlő
Bal Infix Nem Igen
10 & Bitenkénti ÉS Bal Infix Nem Igen
11 ^ Bitenkénti kizáró VAGY Bal Infix Nem Igen
12 | Bitenkénti megengedő VAGY Bal Infix Nem Igen
13 && Logikai ÉS Bal Infix Nem Igen
14 || Logikai(megengedő) VAGY Bal Infix Nem Igen
15 ? : if-then-else operátor Jobb logikai-kif ? kifejezés : kifejezés Nem Nem
16 =
+=
-=
*=
/=
 %=
&=
^=
|=
<<=
>>=
Értékadás
Összeadás és értékadás
Kivonás és értékadás
Szorzás és értékadás
Osztás és értékadás
Maradékképzés és értékadás
Bitenkénti ÉS és értékadás
Bitenkénti kizáró VAGY és értékadás
Bitenkénti megengedő VAGY és értékadás
Eltolás balra és értékadás
Eltolás jobbra és értékadás
Jobb Infix Nem Igen
17 , Szekvencia operátor Bal a, b Nem Igen