Pagina didattica di G. Servizi
Home >> Linguaggio C++ >> vocabolario C++


livello medio

operator

Questa parola, terminata e completata col/coi segno/i caratteristico/i di uno degli operatori del linguaggio C++, o anche col nome di una classe, o anche con le parole di vocabolario new e delete, o anche con una coppia di virgolette, serve a dare il nome a una funzione che effettui il cosiddetto overload dell'operatore coinvolto, oppure a dare la regola di casting tra tipi diversi, oppure a generare un suffisso personalizzato.

Quando si esegue l'overload di un operatore la funzione che lo realizza può essere membro di una class o di una struct oppure può essere qualificata come friend di una certa classe; se invece si vuol definire un suffisso personalizzato la funzione che lo supporta non è membro di nulla.

Se l'operatore coinvolto è un operatore binario (la maggioranza degli operatori) e la funzione operator è membro di una classe, allora DEVE RICEVERE UN SOLO ARGOMENTO, che sarà l'operando destro dell'operatore, restando inteso che l'operando sinistro è l'oggetto istanziato che è responsabile dell'invocazione della funzione.

Se l'operatore coinvolto è un operatore unario e la funzione operator è membro di una classe, allora NON DEVE RICEVERE ALCUN ARGOMENTO dato che l'unico operando necessario si assume ancora una volta essere l'oggetto che ha eseguito la funzione.

Quando la funzione operator non è membro della classe, ma solo, al più, sua friend, il numero di argomenti da trasferirle aumenta di un'unità in ciascuna delle due fattispecie discusse in precedenza, per l'ovvia ragione che, non appartenendo la funzione alla classe, non esiste un meccanismo automatico mediante il quale essa possa conoscere il proprio operando sinistro o l'unico operando.

In NESSUN CASO è lecito utilizzare argomenti standard in una funzione operator.

Pochissimi sono gli operatori del C++ che non possono subire overload tramite una funzione operator; si tratta di:

  1. l'operatore . (punto)

  2. l'operatore :: (risolutore di ambito)

  3. l'operatore .* (puntatore a membro)

  4. l'operatore ternario ? (punto interrogativo)



Tutti gli altri operatori sono passibili di overload, inclusi alcuni assolutamente insospettabili come l'operatore ',' (virgola), l'operatore new, l'operatore delete, l'operatore = (operatore di assegnamento), l'operatore [ ], l'operatore ( ) e l'operatore -> (accesso a membro tramite puntatore).

I lettori più attenti potranno aver notato una sorta di non commutatività degli operatori binari trattati con funzioni operator membri di una classe, anche quando sarebbero commutativi per natura, se non altro per il meccanismo con cui vengono ricevuti gli operandi. Ciò assume rilevanza quando, ad esempio, si volesse scrivere una funzione operator per gli operatori di incremento e decremento (++ e --): come si può distinguere tra la forma prefissa e la forma postfissa di tali operatori che sono entrambi unari? La risposta risiede nel fatto che si può effettuare anche l'overload delle stesse funzioni operator (GRAAAAAANDISSIMO LINGUAGGIO !).

Esempio (da usare solo come pesce d'aprile, se non si vuole farsi maledire da chi lo usasse):

#include <iostream>
using namespace std;

class l_aritmetica_e_un_opinione
{friend ostream & operator << (ostream&, l_aritmetica_e_un_opinione);
int j;
public:
l_aritmetica_e_un_opinione
operator + (l_aritmetica_e_un_opinione),
operator - (l_aritmetica_e_un_opinione),
operator * (l_aritmetica_e_un_opinione),
operator / (l_aritmetica_e_un_opinione);
l_aritmetica_e_un_opinione( ) { }
l_aritmetica_e_un_opinione(int i) {j = i;}};

l_aritmetica_e_un_opinione
l_aritmetica_e_un_opinione :: operator + (l_aritmetica_e_un_opinione ob)
{l_aritmetica_e_un_opinione r;
r.j = j * ob.j;
return r;}

l_aritmetica_e_un_opinione
l_aritmetica_e_un_opinione :: operator - (l_aritmetica_e_un_opinione ob)
{l_aritmetica_e_un_opinione r;
r.j = (int)((float)j / ob.j);
return r;}

l_aritmetica_e_un_opinione
l_aritmetica_e_un_opinione :: operator * (l_aritmetica_e_un_opinione ob)
{l_aritmetica_e_un_opinione r;
r.j = j + ob.j;
return r;}

l_aritmetica_e_un_opinione
l_aritmetica_e_un_opinione :: operator / (l_aritmetica_e_un_opinione ob)
{l_aritmetica_e_un_opinione r;
r.j = j - ob.j;
return r;}

ostream & operator << (ostream & stream, l_aritmetica_e_un_opinione ob)
{stream << ob.j << ' ';
return stream;}

int main( )
{l_aritmetica_e_un_opinione i = 8, j = 5;
cout << "l'oggetto i vale " << i << "l'oggetto j vale " << j << endl;
cout << "ecco quanto vale i+j " << i+j << endl,
cout << "ecco quanto vale i-j " << i-j << endl,
cout << "ecco quanto vale i*j " << i*j << endl,
cout << "ecco quanto vale i/j " << i/j << endl,
cout << "ecco quanto vale i+j/i-i*j: " << i+j/i-i*j << endl;
}

In questo esempio sono definite 4 funzioni operator che stravolgono il significato dei consueti operatori aritmetici: al compilatore non gliene può importare di meno e infatti non fa una piega. Esso applica i suoi criteri di precedenza consueti (* e / hanno sempre precedenza rispetto a + e -, qualunque cosa facciano le funzioni operator), come si vede chiaramente dal risultato dell'ultima operazione.
Si osservi che è stata anche scritta una funzione operator, qualificata friend di l_aritmetica_e_un_opinione, per l'inseritore << su standard output.
In difetto di tale funzione non si sarebbero potuti inserirvi direttamente gli oggetti della class.

Torna in cima alla pagina