puntatore 'questo' in C++
Per comprendere il puntatore 'questo', è importante sapere come gli oggetti guardano le funzioni e i dati membri di una classe.
- Ogni oggetto ottiene la propria copia del membro dati.
- Tutti accedono alla stessa definizione di funzione presente nel segmento di codice.
Ciò significa che ogni oggetto ottiene la propria copia dei membri dati e tutti gli oggetti condividono una singola copia delle funzioni membro.
Quindi ora la domanda è: se esiste una sola copia di ciascuna funzione membro e viene utilizzata da più oggetti, come si accede e si aggiornano i membri dati corretti?
Il compilatore fornisce un puntatore implicito insieme ai nomi delle funzioni come 'questo'.
Il puntatore 'this' viene passato come argomento nascosto a tutte le chiamate di funzioni membro non statiche ed è disponibile come variabile locale all'interno del corpo di tutte le funzioni non statiche. Il puntatore 'this' non è disponibile nelle funzioni membro statiche poiché le funzioni membro statiche possono essere chiamate senza alcun oggetto (con il nome della classe).
Per una classe X, il tipo di questo puntatore è 'X*'. Inoltre, se una funzione membro di X è dichiarata come const, il tipo di questo puntatore è 'const X *' (vedi questo GFact )
Nella prima versione del C++ era possibile modificare il puntatore 'questo'; in questo modo un programmatore potrebbe cambiare su quale oggetto sta lavorando un metodo. Questa funzionalità è stata infine rimossa e ora in C++ è un valore r.
C++ consente agli oggetti di distruggersi chiamando il seguente codice:
delete> this> ;> |
Come ha affermato Stroustrup, 'questo' potrebbe essere il riferimento rispetto al puntatore, ma il riferimento non era presente nella prima versione di C++. Se 'questo' viene implementato come riferimento, il problema di cui sopra potrebbe essere evitato e potrebbe essere più sicuro del puntatore.
Di seguito sono riportate le situazioni in cui viene utilizzato il puntatore 'questo':
1) Quando il nome della variabile locale è uguale al nome del membro
#include> using> namespace> std;> > /* local variable is same as a member's name */> class> Test> {> private> :> > int> x;> public> :> > void> setX (> int> x)> > {> > // The 'this' pointer is used to retrieve the object's x> > // hidden by the local variable 'x'> > this> ->x = x;> > }> > void> print() { cout < <> 'x = '> < < x < < endl; }> };> > int> main()> {> > Test obj;> > int> x = 20;> > obj.setX(x);> > obj.print();> > return> 0;> }> |
Produzione:
x = 20
Per i costruttori, elenco degli inizializzatori può essere utilizzato anche quando il nome del parametro è uguale al nome del membro.
2) Per restituire il riferimento all'oggetto chiamante
/* Reference to the calling object can be returned */> Test& Test::func ()> {> > // Some processing> > return> *> this> ;> }> |
Quando viene restituito un riferimento a un oggetto locale, è possibile utilizzare il riferimento restituito chiamate di funzioni a catena su un unico oggetto.
#include> using> namespace> std;> > class> Test> {> private> :> > int> x;> > int> y;> public> :> > Test(> int> x = 0,> int> y = 0) {> this> ->x = x;> this> ->y = y; }> > Test &setX(> int> a) { x = a;> return> *> this> ; }> > Test &setY(> int> b) { y = b;> return> *> this> ; }> > void> print() { cout < <> 'x = '> < < x < <> ' y = '> < < y < < endl; }> };> > int> main()> {> > Test obj1(5, 5);> > > // Chained function calls. All calls modify the same object> > // as the same object is returned by reference> > obj1.setX(10).setY(20);> > > obj1.print();> > return> 0;> }> |
Produzione:
x = 10 y = 20
Esercizio:
Prevedere l'output dei seguenti programmi. Se ci sono errori di compilazione, correggili.
Domanda 1
#include> using> namespace> std;> > class> Test> {> private> :> > int> x;> public> :> > Test(> int> x = 0) {> this> ->x = x; }> > void> change(Test *t) {> this> = t; }> > void> print() { cout < <> 'x = '> < < x < < endl; }> };> > int> main()> {> > Test obj(5);> > Test *ptr => new> Test (10);> > obj.change(ptr);> > obj.print();> > return> 0;> }> |
Domanda 2
#include> using> namespace> std;> > class> Test> {> private> :> > int> x;> > int> y;> public> :> > Test(> int> x = 0,> int> y = 0) {> this> ->x = x;> this> ->y = y; }> > static> void> fun1() { cout < <> 'Inside fun1()'> ; }> > static> void> fun2() { cout < <> 'Inside fun2()'> ;> this> ->divertimento1(); }> };> > int> main()> {> > Test obj;> > obj.fun2();> > return> 0;> }> |
Domanda 3
#include> using> namespace> std;> > class> Test> {> private> :> > int> x;> > int> y;> public> :> > Test (> int> x = 0,> int> y = 0) {> this> ->x = x;> this> ->y = y; }> > Test setX(> int> a) { x = a;> return> *> this> ; }> > Test setY(> int> b) { y = b;> return> *> this> ; }> > void> print() { cout < <> 'x = '> < < x < <> ' y = '> < < y < < endl; }> };> > int> main()> {> > Test obj1;> > obj1.setX(10).setY(20);> > obj1.print();> > return> 0;> }> |
Domanda 4
#include> using> namespace> std;> > class> Test> {> private> :> > int> x;> > int> y;> public> :> > Test(> int> x = 0,> int> y = 0) {> this> ->x = x;> this> ->y = y; }> > void> setX(> int> a) { x = a; }> > void> setY(> int> b) { y = b; }> > void> destroy() {> delete> this> ; }> > void> print() { cout < <> 'x = '> < < x < <> ' y = '> < < y < < endl; }> };> > int> main()> {> > Test obj;> > obj.destroy();> > obj.print();> > return> 0;> }> |