[C++] Problema con puntatore this
Buongiorno! Sto studiando la OOP dal testo C++ Primer e mi sto interfacciando con il puntatore this. La spiegazione di introduzione non mi è molto chiara. Questo è il codice con la classe:
Ovviamente il codice così com'è scritto non è compilabile, ma non importa questo, importa capire cosa dice il libro.
Dice che quando chiamiamo una funzione membro, noi la chiamiamo su richiesta di un oggetto come per esempio total.isbn(). Quel che non capisco è questo: continua dicendo che quando isbn si riferisce ai membri di Sales_data (come bookNo), esso si sta riferendo implicitamente ai membri dell'oggetto sui quali la funzione è stata chiamata. In questa chiamata quando isbn restituisce bookNo sta implicitamente restituendo total.bookNo e lo fa attraverso un parametro implicito, un puntatore chiamato this. Questo serve a tenere traccia in memoria dell'oggetto total. Non capisco. Cosa c'entra total con bookNo? Sono due variabili diverse, come è possibile scrivere total.bookNo. bookNo non è un metodo.
Potreste chiarirmi questo per favore?
struct Sales_data { std::string bookNo; unsigned units sold = 0; double revenue = 0.0; std::string isbn() const {return bookNo;} Sales_data& combine(const Sales_data&); double avg_price() const; }; Sales_data total; if(read(cin, total)) { Sales_data trans; while(read(cin, trans)) if(total.isbn() == trans.isbn()) total.combine(trans); else { print(cout, total) << endl; total = trans; } print(cout, total) << endl; } else { cerr << "No Data!" << endl; } }
Ovviamente il codice così com'è scritto non è compilabile, ma non importa questo, importa capire cosa dice il libro.
Dice che quando chiamiamo una funzione membro, noi la chiamiamo su richiesta di un oggetto come per esempio total.isbn(). Quel che non capisco è questo: continua dicendo che quando isbn si riferisce ai membri di Sales_data (come bookNo), esso si sta riferendo implicitamente ai membri dell'oggetto sui quali la funzione è stata chiamata. In questa chiamata quando isbn restituisce bookNo sta implicitamente restituendo total.bookNo e lo fa attraverso un parametro implicito, un puntatore chiamato this. Questo serve a tenere traccia in memoria dell'oggetto total. Non capisco. Cosa c'entra total con bookNo? Sono due variabili diverse, come è possibile scrivere total.bookNo. bookNo non è un metodo.
Potreste chiarirmi questo per favore?
Risposte
"ZfreS":
Cosa c'entra total con bookNo? Sono due variabili diverse, come è possibile scrivere total.bookNo. bookNo non è un metodo.
Tramite il punto puoi accedere a tutti i membri di una classe, inclusi i "data members", non solo ai metodi. [inline]total[/inline] è un'istanza della classe [inline]Sales_data[/inline], e come tale possiede un [inline]bookNo[/inline].
Quindi il in realtà il metodo isbn() quando chiamato sull'oggetto total si riferisce implicitamente sia a bookNo, sia a units_sold, sia a revenue, giusto?
L'istruzione [inline]total.isbn()[/inline] restituisce il valore di [inline]total.bookNo[/inline], se è questo che stai chiedendo. [inline]units_sold[/inline] e [inline]revenue[/inline] non c'entrano qui.
Magari dai un'occhiata qui:
http://www.bo.cnr.it/corsi-di-informatica/corsoCstandard/Lezioni/27Classi.html
l'ultimo paragrafo spiega l'argomento in modo abbastanza semplice ed esaustivo.
http://www.bo.cnr.it/corsi-di-informatica/corsoCstandard/Lezioni/27Classi.html
l'ultimo paragrafo spiega l'argomento in modo abbastanza semplice ed esaustivo.
Forse è un po' tecnico ma puoi leggere una documentazione completa su quella keyword a questa pagina: https://en.cppreference.com/w/cpp/language/this
In generale, devi capire che una funzione membro (non statica) è in realtà una funzione normale in cui il primo parametro è il puntatore a [inline]this[/inline]. Insomma, anche se non ti è possibile scriverlo in maniera esplicita[nota]Insomma ciò che è vero a livello semantico non è necessariamente vero a livello di codice prodotto dal compilatore. A livello di codice prodotto, le due cose sono equivalenti, ma non lo sono all'interno della semantica del C++.[/nota], ti conviene pensare [inline]total.isbn( )[/inline] come [inline]isbn( &total )[/inline] e [inline]this[/inline] come il nome di quello specifico puntatore all'interno della funzione membro.
Non puoi assegnare una funzione membro ad un normale puntatore a funzione (devi usare un puntatore a funzione membro), ma un modo in cui puoi vedere esplicitamente l'equivalenza è attraverso l'oggetto std::function. Infatti puoi scrivere:
In generale, devi capire che una funzione membro (non statica) è in realtà una funzione normale in cui il primo parametro è il puntatore a [inline]this[/inline]. Insomma, anche se non ti è possibile scriverlo in maniera esplicita[nota]Insomma ciò che è vero a livello semantico non è necessariamente vero a livello di codice prodotto dal compilatore. A livello di codice prodotto, le due cose sono equivalenti, ma non lo sono all'interno della semantica del C++.[/nota], ti conviene pensare [inline]total.isbn( )[/inline] come [inline]isbn( &total )[/inline] e [inline]this[/inline] come il nome di quello specifico puntatore all'interno della funzione membro.
Non puoi assegnare una funzione membro ad un normale puntatore a funzione (devi usare un puntatore a funzione membro), ma un modo in cui puoi vedere esplicitamente l'equivalenza è attraverso l'oggetto std::function. Infatti puoi scrivere:
std::function< std::string(Sales_data *) > isbn = &Sales_data::isbn;
@ Raptorista Penso di aver risolto il problema. Il metodo isbn viene tradotto come total.bookNo perchè deve restituire un bookNo. Non avevo fatto attenzione al dato restituito.
@ supersquirrel, @ vict85
Grazie ad entrambi per i link, ho capito più da lì che dal libro. Il c++ primer lo conoscete?
@ supersquirrel, @ vict85
Grazie ad entrambi per i link, ho capito più da lì che dal libro. Il c++ primer lo conoscete?
Se parli di quello di Lippman (ovvero quello senza il plus nel nome) è un libro abbastanza apprezzato (io non l'ho mai letto), ma non per principianti. Insomma, come il manuale di Stroustrup, si tratta più di un libro di riferimento che un vero e proprio manuale per imparare. Sinceramente, non sono sicuro quanto siano davvero utili questo genere di libri dato che puoi ormai guardare le varie cose in siti tipo quello che ti ho mandato. Insomma dopo aver imparato le basi e fatto esperienza "sul campo", ritengo che tu possa aver più bisogno di libri su argomenti specifici piuttosto che su tutto il C++. Per esempio, esistono libri sull'uso dei puntatori, sui template, sulla libreria standard, sulla programmazione parallela, programmazione sicura e libri di consigli come i libri di Scott Meyers (Effective C++ e successivi).
Giusto per completezza sull'argomento libri, segnalo una guida abbastanza nota alla scelta di un buon libro per il C++
https://stackoverflow.com/questions/388 ... e-and-list
https://stackoverflow.com/questions/388 ... e-and-list
Si, io ho il Lippman ma nella guida suggerita da Raptorista considera quel libro come principiante, cosa che in realtà non è. Infatti mi sto apoggiando anche ad un altro testo.
Riprendo questo thread per un altro dubbio riguardante il puntatore this suscitato leggendo del codice sulla gestione network delle qt. Il pezzo di codice è questo:
Non capisco quale sia il ruolo del this. In generale cosa significa l'espressione:
Potreste chiarirmi questo dubbio per favore?
QNetworkAccessManagermanager = new QNetworkAccessManager(this);
Non capisco quale sia il ruolo del this. In generale cosa significa l'espressione:
A *a = new A(this)dove A è una classe.
Potreste chiarirmi questo dubbio per favore?
Il this non svolge alcun ruolo particolare in quel codice. Insomma, sta semplicemente allocando dinamicamente un oggetto di tipo \(A\) e inizializzando la memoria usando un particolare costruttore (che ha come parametro un puntatore alla classe di partenza).
Questo tipo di approccio è abbastanza usato, anche se l'ho visto più spesso usare legato agli smart pointers. In ogni caso puoi cercare di capire quella linea nel seguente esempio:
Questo tipo di approccio è abbastanza usato, anche se l'ho visto più spesso usare legato agli smart pointers. In ogni caso puoi cercare di capire quella linea nel seguente esempio:
#include <stdint.h> #include <iostream> class B; class A final { public: A( B* b ) : b( b ){}; void print( ) const; private: B* b; }; class B final { public: B( ) : value( 0 ) , a( nullptr ){}; ~B( ) { if ( a ) delete a; }; A* get_a( ) { if ( !a ) { a = new A( this ); } return a; } void set_value( uint32_t new_value ) { value = new_value; } uint32_t get_value( ) const { return value; } private: uint32_t value; A* a; }; void A::print( ) const { std::cout << ( b ? b->get_value( ) : 0 ) << std::endl; }; int main( ) { B b; const A* a = b.get_a( ); a->print( ); b.set_value( 121 ); a->print( ); }
"ZfreS":
Riprendo questo thread per un altro dubbio riguardante il puntatore this suscitato leggendo del codice sulla gestione network delle qt. Il pezzo di codice è questo:
QNetworkAccessManagermanager = new QNetworkAccessManager(this);
Non capisco quale sia il ruolo del this. In generale cosa significa l'espressione:
A *a = new A(this)dove A è una classe.
Potreste chiarirmi questo dubbio per favore?
Gli oggetti della libreria Qt si auto-organizzano in alberi[nota]Quelli relativi a classi che ereditano da QObject[/nota].
L'oggetto che stai creando ha come "padre" (parent) l'oggetto *this.
Quando un oggetto viene distrutto (tramite delete o perché esce dallo scope), distrugge ricorsivamente a sua volta tutti i suoi oggetti figli (children).
https://doc.qt.io/qt-5/objecttrees.html
Puoi evitare questo comportamento passando nullptr invece di this, ma dovrai tenere traccia e distruggere manualmente i tuoi oggetti.
In generale, come dice vict85, stai semplicemente passando un puntatore a un costruttore.
Ho capito, grazie mille!