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 dell’Automazione
Lezione 5
Sovraccarico degli operatori
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 &


Operatore di assegnamento =




Restituisce l’indirizzo dell’oggetto
Esegue una copia membro a membro
Entrambi possono comunque essere ridefiniti
Non è possibile ridefinire operatori che
operano sui tipi predefiniti
Non è possibile cambiare l’arità o
l’associatività di un operatore
Associatività degli operatori

Per tutti gli operatori l’associatività è
da sinistra a destra

Tranne = per cui l’associatività è 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

L’assegnamento 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<operatore>
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)

L’argomento è un oggetto della classe o un suo
riferimento

È necessario che sia un riferimento quando si deve
modificare l’oggetto
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 l’oggetto
Quando l’operatore viene definito tramite una funzione
membro, l’oggetto alla sinistra dell’operatore invoca
l’operatore 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 dell’oggetto
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 l’operazione riguarda oggetti di tipi
diversi

Es. * vettore-matrice, - magazzino-ordine
Sovraccarico di << e >>

Gli operatori << e >> (inserimento ed estrazione da uno stream)
vanno ridefiniti tramite operatori friend per poterli usare su oggetti
definiti dall’utente
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 dell’operatore []

const e non const
 Passare
ad una funzione un array const e
poi utilizzare l’operatore per accedere al
contenuto modificandolo sarebbe un
problema

Il compilatore non consente l’uso di funzioni
membro non const con oggetti const
Scarica

Lezione 5