Elementi di programmazione ad oggetti a. a. 2009/2010 Corso di Laurea Magistrale in Ingegneria Elettronica Docente: Mauro Mazzieri, Dipartimento di Ingegneria Informatica, Gestionale e dellAutomazione
Lezione 5 Sovraccarico degli operatori
Il meccanismo del sovraccarico delle funzioni vale anche per gli operatori predefiniti Gli operatori non sono altro che funzioni in forma infissa a *= 5 equivale a a.operator*=(5) Il sovraccarico consente di ridefinire il comportamento degli operatori predefiniti Non è possibile creare nuovi operatori
Operatori ridefinibili È possibile ridefinire gli operatori + - * / % ^ & | ~ ! = += -= *= /= %= ^= &= |= > >>= = && || >*, -> [] () new new[] delete delete[] Non è possibile ridefinire gli operatori ::..* ?: sizeof typeid
Definire un operatore Affinché un operatore possa operare sui membri di una classe deve essere ridefinito Fanno eccezione Operatore di indirizzo & Restituisce lindirizzo delloggetto Operatore di assegnamento = Esegue una copia membro a membro Entrambi possono comunque essere ridefiniti Non è possibile ridefinire operatori che operano sui tipi predefiniti Non è possibile cambiare larità o lassociatività di un operatore
Associatività degli operatori Per tutti gli operatori lassociatività è da sinistra a destra Tranne = per cui lassociatività è da destra a sinistra z+y+z viene valutata come (x+y)+z x=y=z viene valutata come x=(y=z)
Assegnamento membro a membro Lassegnamento di un oggetto ad un altro oggetto viene gestito di default come una copia membro a membro unOggetto = unAltroOggetto; Non viene utilizzato il costruttore per copia ma un operatore implicito di assegnamento Ad ogni membro non statico di unOggetto viene assegnato il corrispondente valore del membro di unAltroOggetto Dopo la copia, i due oggetti hanno gli stessi dati, ma rimangono due oggetti distinti
Definizione di un operatore Il sovraccarico di un operatore si esegue definendo una funzione il cui nome è operator class Complex { double re, im; public: Complex& operator+(Complex c) { re += c.re; im += c.im; return *this; } };
Sovraccarico di un operatore unario Un operatore unario può essere definito come funzione membro (senza argomenti) o funzione non membro (con un argomento) Largomento è un oggetto della classe o un suo riferimento È necessario che sia un riferimento quando si deve modificare loggetto Complex& Complex::operator-() { re = -re; im = -im; return *this; }
Sovraccarico di un operatore binario Un operatore binario può essere definito come funzione membro (con un argomento) o funzione non membro (con due argomenti) Gli argomenti sono oggetti della classe o loro riferimenti È necessario che sia un riferimento quando si deve modificare loggetto Quando loperatore viene definito tramite una funzione membro, loggetto alla sinistra delloperatore invoca loperatore e quello sulla destra viene passato come argomento Complex& Complex::operator-(Complex& c) { re -= c.re; im -= c.im; return *this; }
Valore di ritorno di un operatore Un operatore può restituire una copia delloggetto risultato o un riferimento Complex& Complex::operator-(Complex& c) { re -= c.re; im -= c.im; return *this; } Complex Complex::operator-(Complex& c) { re -= c.re; im -= c.im; return *this; }
Operatori friend Un operatore che ha bisogno di accedere ai dati privati di un oggetto può essere definito come friend invece che come membro Le funzioni friend non hanno un puntatore this, per cui bisogna passare esplicitamente entrambi i parametri Gli operatori friend sono utili in quei casi in cui loperazione riguarda oggetti di tipi diversi Es. * vettore-matrice, - magazzino-ordine
Sovraccarico di > Gli operatori > (inserimento ed estrazione da uno stream) vanno ridefiniti tramite operatori friend per poterli usare su oggetti definiti dallutente class Complex { // … friend std::ostream& operator<<(std::ostream&, const Complex); friend std::istream& operator>>(std::istream&, Complex&); }; std::ostream& operator<<(std::ostream& o, const Complex c) { return o << "(" << c.re << ", " << c.im << ")"; } std::istream& operator>>(std::istream& i, Complex& c) { i >> c.re >> c.im; return i; }
Operatori new e delete new e delete sono degli operatori, ed in quanto tali possono essere ridefiniti void* operator new(size_t size) { // Esegue l'allocazione. // Restituisce un puntatore alla memoria allocata, oppure 0 } void operator delete(void* p) { // rilascia la memoria } Quando viene chiamato new, viene automaticamente chiamato il costruttore appropriato Quando viene chiamato delete, viene automaticamente chiamato il distruttore
new e delete su array void* operator new[](size_t size) { // Esegue l'allocazione. // Restituisce un puntatore alla memoria allocata, oppure 0 } void operator delete[](void* p) { // Rilascia la memoria. // Il distruttore di ogni elemento viene chiamato automaticamente }
Operatore [] Esistono due versioni delloperatore [] const e non const Passare ad una funzione un array const e poi utilizzare loperatore per accedere al contenuto modificandolo sarebbe un problema Il compilatore non consente luso di funzioni membro non const con oggetti const