Egyet s mást az operátorokról

A C++ egyik legérdekesebb tulajdonsága az, hogy a már meglévő operátorokat (vagyis műveleti jeleket) felül tudjuk definiálni, amivel növelni tudjuk az általunk írt kód rugalmasságát. Ez az igencsak hasznos tulajdonság ebben a pillanatban (ha nem tudom jól, kérem, javítsanak ki) csak és kizárólag a C++ programozási nyelv tulajdonsága, és más programozási nyelvekben még nem található meg, úgyhogy szerintem érdemes egy cikk erejéig foglalkozni vele.

Operátorokat deklarálhatunk mint osztály függvény, amikor is ha két paramétert vár el az operátor (mint például a + operátor), akkor az első paraméter automatikusan az objektum lesz, amely meghívja az operátort, és a deklarációnál csak egy paramétert kell megadnunk, illetve mint "normális" függvény, ezen esetben meg kell adnunk a teljes paraméterezést az operátornak.

Vegyük például a Complex osztály deklarációját:

class Complex {

private:

       float re, im;

public:

       Complex(float a, float b);

       Complex operator + (complex a);

       Complex operator - (complex a);

       Complex operator * (complex a);

       Complex operator / (complex a);

};

Amikor magukat az operátorokat definiáljuk, a következőképpen járunk el:

Complex Complex::operator + (Complex a) {

Complex c;

       c.re = re + a.re;

       c.im = im + a.im;

       return c;

}

Ha viszont mint függvény definiálunk egy operátort, akkor a következőképpen alakul a forráskódunk:

bool operator == (Complex a, Complex b)

{

   ...

}

Ezen esetben viszont tartsuk a szem előtt azt, hogy az osztálynak a privát tagjaihoz csak akkor lesz hozzáférése a függvénynek, hogyha friend (barát) függvényként deklaráljuk az osztályban:

class Complex {

       ....

       friend Complex operator + (Complex a, Complex b);

       ....

};

Az operátorok felüldefiniálásánál a következőkre kell figyelmet fordítanunk:

  • Csak a már létező operátorokat tudjuk felüldefiniálni, kivétel a következők, melyek esetében ez a művelet nem megengedett: . .* :: ?: # ##
  • Az operátoroknál, melyeket nem osztály függvényként definiálunk, kötelező módon az egyik paraméternek osztály típusúnak kell lennie.
  • A következő két módszer egyenértékű: a.operator+(b); (hosszú mód) illetve a+b; (rövid mód), ahol a és b az előbb bemutatott Complex osztály egy-egy példánya.
  • Mind a ++ illetve -- operátorokat felül lehet definiálni. A prefix változat, mint függvény, egy paramétert vár el, amikor deklaráljuk valamelyik operátort. Ezzel szemben postfix változat két paramétert vár el, a másodiknak kötelező módon int típusúnak kell lennie. Amennyiben osztályfüggvényekként szerepelnek, akkor a prefixnek nincs, a postfixnek viszont van egy darab, mégpedig int típusú paramétere. Amikor a postfix változatot hívjuk a rövid módon, akkor a C++ automatikusan egy zérót helyez a paraméter helyére. Például tekintsük a Complex osztályt megint:

class Complex {

       ...

       Complex(float a=0, float b=0);

       Complex operator ++ (); //a prefix operátor

       Complex operator ++ (int); //postfix forma

       ...

};

Complex c;

++c; //egyenértékü a következővel: c.operator++()

c++; //egyenértékü: c.operator++(0)

  • Csak az értékadás és az address-of operátorok vannak definiálva egy osztály számára, minden más operátort nekünk kell definiálni.
  • A következő operátorokat csak osztályfüggvényként lehet újradefiniálni: = () [] ->
  • A -> operátor, annak ellenére, hogy bináris operátor (két paramétere van eredetileg, pld pStr->iCount), csak unáris operátorként lehet felüldefiniálni, ami visszatérít egy "osztályra mutató pointer" típust, vagy egy "osztálypéldány, melynek szintén felül van definiálva a -> operátora" típust.
  • Felüldefiniált operátorfüggvényeknek nem lehet alapértelmezett paramétere.

A new operátor

A new operátort felüldefiniálhatjuk a következőképpen, ha nem mint osztályfüggvény akarjuk használni, hanem a "placement" szintaxist akarjuk követni (placement - elhelyezés):

void *operator new (size_t s, paraméterek...);

Amikor a placement szintaxist használjuk, akkor ez az operátor kerül meghívásra:

new (paraméterek)Tipus;

new (paraméterek)OsztályTipus(paraméterek);

Ha a new operátort egy osztály függvényeként deklaráltuk, akkor automatikusan statikus függvényként fog szerepelni. Az első paraméter itt is size_t típus, és a C++ fordító automatikusan létrehozza ezt az értéket, úgyhogy, nekünk nincs gondunk vele.

A delete operátor

A C++-ban nincs lehetőség felüldefiniálni a globális delete operátort, viszont osztályspecifikus delete operátor létrehozására van lehetőségünk. A delete operátor osztályfüggvénye szintén statikus metódus lesz, csakúgy, mint a new operátoré.

A delete operátor metódusai mind void típusú függvények, vagyis nincs visszatérési értékük. Az első paraméterük egy void* érték, ami a törlendő objektum címét tartalmazza, míg a második, opcionális size_t paraméter, ami az adott típus méretét tárolja.

Ennyit az operátorokról, legközelebb a sablonok kerülnek mikroszkóp alá.

Deák Ferenc