Il puntatore this Quando vogliamo accedere a un - TelPar

Download Report

Transcript Il puntatore this Quando vogliamo accedere a un - TelPar

Appunti di OOP in C++
telpar.altervista.org
Il puntatore this
Quando vogliamo accedere a un oggetto abbiamo bisogno di un handle (maniglia) ossia un
puntatore o un reference che punti all'indirizzo iniziale di memoria dove è memorizzato
quest'oggetto.
Il puntatore this è un particolare puntatore, costante1, che contiene l'indirizzo iniziale di memoria
dove è memorizzato l'oggetto proprio.
L'oggetto si ritiene ovviamente “vivente”...ovvero già allocato in memoria (compito svolto dal
compilatore) e inizializzato (compito svolto dal costruttore).
Quindi, ogni oggetto in memoria può accedere al proprio indirizzo tramite questo puntatore.
Quando richiamiamo una funzione membro (non statica) su un oggetto avviene un'attività nascosta
da parte del compilatore, il quale aggiunge implicitamente, prima di ogni altro eventuale
paramentro, un extra parametro ovvero proprio l'indirizzo iniziale dove si trova l'oggetto, cioè il
puntatore this.
Esempio di chiamata della funzione membro print sull'oggetto data:
C data; // data è un oggetto della classe C
data.print(); ... il compilatore “la trasforma” in .... print(&data);
data.set(5); ...il compilatore “la trasforma” in .... set(&data, 5);
A livello di prototipo, il compilatore modifica quello specificato nel sorgente aggiungedogli l'extra
parametro this, che, come detto, è un particolare puntatore, che punta a un oggetto di classe C. Il
prototipo della funzione print() dichiarata pubblica nel corpo dichiarativo di C, diventa:
void print() const; ... il compilatore la trasforma in ... void print (C* const this);
void set(int v); ... il compilatore la trasforma in ... void set(C* const this, int v);
Dunque il tipo di this dipende dal tipo dell'oggetto e dal fatto che la funzione membro in cui viene
chiamata sia dichiarata costante o meno; nel primo caso anche il puntatore sarà costante (e quindi si
potrà accedere all'oggetto solo in lettura), nel secondo caso, invece, il puntatore non sarà costante e
quindi si potrà accedere all'oggetto anche in scrittura.
Quindi, anche se una funzione membro non ha parametri, comunque avrà come unico parametro
formale, “segreto” (cioè nascosto al programmatore), un puntatore costante di nome “this”.
Se ha più di un parametro, il primo parametro nascosto sarà sempre il puntatore this.
All'atto della chiamata, &data (l'indirizzo dove si trova l'oggetto), il parametro attuale, viene
ricopiato in this, il parametro formale, e grazie a questo puntatore la funzione print() accede
all'oggetto data.
1 Per puntatore costante si intende un puntatore che deve essere inizializzato all'atto della definizione e non può più
essere modificato, durante tutto il suo ciclo di vita, ovvero fargli cambiare l'oggetto cui punta
Appunti di OOP in C++
telpar.altervista.org
Ecco perché, quando chiamiamo una funzione su un oggetto non c'è bisogno di passargli l'oggetto;
lo fa per noi il compilatore, in modo del tutto implicito, aggiungendo un parametro “segreto” cioè
this.
Come ogni puntatore a una struttura è possibile accedere ai vari campi mediante una
deferenziazione dello stesso.
Possono accedere al puntatore this solo le funzioni membro non statiche.
N.B. Il puntatore this non esiste per i membri statici.
Esempio di utilizzo di this:
class C
{
public:
C(int a=0);
void print() const;
private:
int x;
};
C::C(int a)
{ x = a; }
void C::print() const
{
cout << this->x << endl;
}
// oppure cout << (*this).x << endl
// oppure ancora cout << x << endl
int main() {
C oggetto(12);
oggetto.print();
}
USARE THIS PER EFFETTUARE CHIAMATE A CASCATA
Se this è il puntatore all'oggetto, *this conterrà l'indirizzo all'oggetto. Alcune volte *this viene
ritornato come reference all'oggetto per effettuare chiamate in cascata (v. Deitel pag. 418)
Es.
Orario& Orario::setOra(int h=0)
{
if ( (ora>0) && (ora<24) ) // check dell'arg.
ora = h
else
ora = 0;
return *this; // Ritorna un reference a un oggetto Orario
}
Appunti di OOP in C++
telpar.altervista.org
Orario& Orario::setminuti(int m=0)
{
if ( (m>0) && (m<24) ) // arg check
min = m
else
ora = 0;
return *this; // Ritorna un reference a un oggetto Orario
}
Es.
Orario sveglia;
sveglia.setOra(6).setMinuti(30);
Da sinistra a destra; l'invocazione sveglia.setOra ritorna un reference a un oggetto di classe Orario sul
quale viente poi invocato il metodo setMinuti()