appunti3s:references
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revision | |||
appunti3s:references [2013/10/06 15:01] – profpro | appunti3s:references [2020/06/08 22:20] (current) – external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== Premessa per chi conosce i puntatori====== | ||
+ | NOTA BENE: in questo capitolo mancano di proposito il concetto di puntatore e di variabile globale: questa premessa è solo per chi già li conoscesse. Chi non conosce i puntatori deve saltare questo paragrafo e passare a quello sottostante | ||
+ | |||
+ | Sia nel linguaggio C che in C++ si può effettuare il passaggio di parametri esclusivamente //per valore//, cioè copiando il contenuto delle variabili indicate tra parentesi. | ||
+ | Vedere esempio [[appunti3s: | ||
+ | Questo impedisce di effettuare delle modifiche sui //parametri effettivi// della funzione. | ||
+ | < | ||
+ | { | ||
+ | | ||
+ | // il risultato deve essere restituito | ||
+ | | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Tuttavia, se al posto dei tradizionali tipi di dato (come //int//) si usano i puntatori (come //int*//), la funzione riesce ad accedere e a modificare anche i //parametri effettivi// | ||
+ | < | ||
+ | { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | </ | ||
+ | Come si può notare dal secondo esempio, questo appesantisce il codice costringendo ad aggiungere l' | ||
+ | |||
+ | I // | ||
+ | |||
+ | ====== References ====== | ||
+ | |||
+ | Quando una funzione ha come //parametro formale// un reference, al suo interno NON viene creata una nuova variabile locale, ma si lavora proprio sul //parametro effettivo// usando il nome del parametro formale come il suo soprannome temporaneo. | ||
+ | |||
+ | < | ||
+ | La dichiarazione si legge in questo modo: | ||
+ | la funzione accetta come argomento un //reference a...// intero. | ||
+ | La chiamata della funzione, invece, è come quella vista nel passaggio per valore... | ||
+ | < | ||
+ | |||
+ | Nella seguente figura le funzioni main() e calcolaTriplo() sono rappresentate da due contenitori. la variabile //x// non ha una propria area di memoria, ma è solo il soprannome (alias) della variabile mioNumero. // | ||
+ | |||
+ | {{ : | ||
+ | ===== Un solo simbolo con molti significati ===== | ||
+ | |||
+ | Purtroppo il simbolo //&//, usato in un altro luogo, possiede anche altri significati, | ||
+ | Il reference al momento della sua dichiarazione __deve__ essere sempre inizializzato, | ||
+ | |||
+ | <file cpp 22.cpp> | ||
+ | // Questo programma è stato scritto da Fabio. | ||
+ | // Serve a calcolare il triplo di un numero. | ||
+ | |||
+ | #include < | ||
+ | |||
+ | // questo modo di passare il parametro | ||
+ | // non crea una copia locale | ||
+ | // questa funzione e' di tipo void, cioe' non restituisce nulla (manca return) | ||
+ | |||
+ | void calcolaTriplo(int& | ||
+ | { | ||
+ | x = 3*x; | ||
+ | } | ||
+ | |||
+ | int main () | ||
+ | { | ||
+ | int mioNumero; | ||
+ | |||
+ | std::cout << "Per favore scrivi un numero intero: "; | ||
+ | std::cin >> mioNumero; | ||
+ | | ||
+ | calcolaTriplo(mioNumero); | ||
+ | | ||
+ | std::cout << "il triplo vale " << mioNumero << " | ||
+ | return 0; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ===== references costanti ===== | ||
+ | |||
+ | Premettendo //const// davanti ad un reference si __impedisce__ di modificare il //parametro effettivo// | ||
+ | |||
+ | Questo è utilizzato soprattutto quando il parametro effettivo è un " | ||
+ | |||
+ | <file cpp 23.cpp> | ||
+ | // Questo programma è stato scritto da Fabio. | ||
+ | |||
+ | #include < | ||
+ | |||
+ | // questo modo di passare il parametro permette di agire sul parametro effettivo | ||
+ | // NON passa una copia | ||
+ | // il termine const evita modifiche indesiderate al parametro passato. | ||
+ | // NON crea una nuova copia della variabile, si risparmia memoria! | ||
+ | // x è solo il soprannome temporaneo che viene dato a mioNumero | ||
+ | |||
+ | int calcolaTriplo(const int& x) | ||
+ | { | ||
+ | | ||
+ | } | ||
+ | |||
+ | int main () | ||
+ | { | ||
+ | int mioNumero; | ||
+ | |||
+ | std::cout << "Per favore scrivi un numero intero: "; | ||
+ | std::cin >> mioNumero; | ||
+ | | ||
+ | std::cout << "il triplo di " << mioNumero | ||
+ | << " vale " << calcolaTriplo(mioNumero) " | ||
+ | return 0; | ||
+ | } | ||
+ | </ | ||
+ | Per comprendere il risparmio di memoria ottenuto con i references costanti, confrontare la seguente tabella di traccia con quella ottenuta con il [[appunti3s: | ||
+ | |||
+ | ^mioNumero (alias x) ^ output ^ | ||
+ | | 6 | - | | ||
+ | | 6 | - | | ||
+ | | 6 | 18 | | ||
+ | |||
+ | |||
+ | I const reference sono anche l' | ||
+ | |||
+ | vedere //Thinking in C++, capitolo 11: References & the Copy-Constructor pag.477// | ||
+ | |||
+ | ===== Funzioni costanti ===== | ||
+ | |||
+ | Le funzioni costanti sono importanti perché sono un buono strumento per evitare errori. | ||
+ | Basta aggiungere il modificatore //const// in fondo della dichiarazione della funzione (prima del punto e virgola). Questo impedisce modifiche accidentali ai dati. | ||
+ | Il compilatore controllerà che questa funzione non esegua alcuna istruzione di modifica su NESSUNO dei dati passati. Se il programmatore non rispetta questa regola, verrà avvisato dal compilatore. Per questo motivo //const// dovrebbe essere usato su tutte le funzioni di tipo // | ||
+ | |||
+ | Le funzioni costanti (quindi, ispettrici) sono anche le uniche che possono avere come argomenti interi oggetti costanti come: | ||
+ | |||
+ | * fun(const int& x) const | ||
+ | * fun(const Classe unOggetto) const | ||
+ | * fun(const Classe& unOggetto) const | ||
+ | * fun(const Classe* unOggetto) const | ||
+ | Infatti, provando a passare un oggetto __costante__ ad una funzione //non costante// si ottiene errore. | ||
+ | * fun(const Classe unOggetto) | ||
+ | Questo perché una tale funzione (non ispettrice, ma modificatrice) dovrebbe consentire di modificare l' | ||
+ | |||
+ | ====Errore da evitare==== | ||
+ | Restituire un reference (return) è un' | ||
+ | |||
+ | Per approfondire si può studiare il seguente esempio, dove l'uso dei reference costanti è corretto. | ||
+ | |||
+ | <file cpp 24.cpp> | ||
+ | // Questo programma è stato scritto da Fabio. | ||
+ | |||
+ | // Serve a calcolare il triplo di un numero. | ||
+ | // I reference sono utili per risparmiare memoria | ||
+ | // anche sul tipo restituito dalla funzione | ||
+ | // basta aggiungere UN SECONDO reference (sempre preceduto da un const) | ||
+ | // ma e' molto facile commettere errori... | ||
+ | |||
+ | #include < | ||
+ | |||
+ | const int& triplicare(const int& x) | ||
+ | { | ||
+ | | ||
+ | } | ||
+ | |||
+ | int main () | ||
+ | { | ||
+ | int mioNumero; | ||
+ | |||
+ | std::cout << "Per favore scrivi un numero intero: "; | ||
+ | std::cin >> mioNumero; | ||
+ | | ||
+ | std::cout << "il triplo di " << mioNumero | ||
+ | << " vale " << triplicare(mioNumero) " | ||
+ | return 0; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Il nuovo alias davanti alla funzione evita di creare una nuova variabile temporanea che sarebbe necessaria anche per restituire il valore con // | ||
+ | Il nuovo //const// davanti alla funzione impedisce modifiche indesiderate a tale oggetto. | ||
+ | In questo caso restituire un reference è corretto perché l' | ||
+ | |||
+ | ===== Esempi ===== | ||
+ | I reference sono un nuovo tipo del C++ quindi, tutte le funzioni che usano il tipo reference sono utilizzate sempre con la dot notation... | ||
+ | (Fare prima la programmazione orientata agli oggetti e DOPO i reference?) | ||
+ | |||
+ | - int compare ( const string& str ) const; | ||
+ | - int find ( char c, size_t pos = 0 ) const; | ||
appunti3s/references.txt · Last modified: 2020/06/08 22:20 by 127.0.0.1