====== Premessa ====== 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:programmi_procedurali#passaggio_per_valore]]. Questo impedisce di effettuare delle modifiche sui //parametri effettivi// della funzione. int triplicare(int x) { x=x*3; // modifica solo la var. locale x return x; } 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 //parametro effettivi//. int triplicare(int* p) { *p=*p*3; // modifica anche la variabile puntata da p return *p; } Come si può notare dal secondo esempio, questo appesantisce il codice costringendo ad aggiungere l'operatore di deferimento //*// (l'asterisco) davanti al puntatore //p//. I //references//, invece, hanno la stessa "forza" dei puntatori, ma una sintassi molto semplice. ====== References ====== Quando una funzione ha come //parametro formale// un reference, al suo interno NON viene crea una nuova variabile locale, ma si lavora proprio sul //parametro effettivo// usando il parametro formale come il suo soprannome temporaneo. void triplicare(int& x); La dichiarazione si legge in questo modo: la funzione accetta come argomento un //reference a...// intero. Purtroppo il simbolo //&//, usato in un altro luogo, possiede anche altri significati, completamente diversi. Dentro un'espressione logica può significare operatore //AND binario//, oppure scirtto davanti al nome di una variabile, operatore //indirizzo di//. Il reference al momento della sua dichiarazione __deve__ essere sempre inizializzato, infatti non si può usare un soprannome senza dire a chi corrisponde quell'alias... Al contrario dei puntatori, i reference, una volta inizializzati come alias ad un oggetto, non possono diventare l'alias di niente altro. // 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 triplicare(int& x) { x = 3*x; } int main () { int mioNumero,mioTriplo; std::cout << "Per favore scrivi un numero intero: "; std::cin >> mioNumero; triplicare(mioNumero); // chiamata della funzione che modifica il mioNumero std::cout << "il triplo vale " << mioNumero << ".\n"; return 0; } ====== references costanti ====== Premettendo //const// davanti ad un reference si __impedisce__ di modificare il //parametro effettivo//. L'effetto è simile al classico passaggio per valore, ma con la differenza che invece di creare una copia del parametro effettivo, in pratica si copia solo il suo indirizzo. Questo è utilizzato soprattutto quando il parametro effettivo è un "oggetto" (difficile da copiare o di notevoli dimensioni). // Questo programma è stato scritto da Fabio. #include // questo modo di passare il parametro // passa l'indirizzo di memoria di questo parametro // il termine const evita modifiche indesiderate al parametro. // NON creando una nuova variabile x, risparmio memoria! // x è solo il soprannome temporaneo che viene dato a mioNumero int triplicare(const int& x) { return 3*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) ".\n"; return 0; } // 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) #include const int& triplicare(const int& x) { return 3*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) ".\n"; return 0; } Il nuovo alias davanti alla funzione evita di creare una nuova variabile temporanea che sarebbe necessaria anche per restituire il valore con //return//. Il nuovo //const// davanti alla funzione impedisce modifiche indesiderate a tale oggetto locale. I const reference sono anche l'unico modo con cui si possono utilizzare gli oggetti temporanei inaccessibili (come le espressioni costanti o gli oggetti temporanei restituiti da una funzione) vedere //Thinking in C++, capitolo 11: References & the Copy-Constructor pag.477// ====== Funzioni costanti ====== Le funzioni costanti sono importanti perché sono un buono strumento di correzione degli errori. Basta aggiungere un modificatore //const// in fondo (alla fine) della firma della funzione. Questo evita modifiche accidentali ai dati degli oggetti Basta scrivere //const// __in fondo__ al nome della funzione per costringere il compilatore a fare un controllo che quella funzione non esegua alcuna istruzione di modifica su TUTTI i membri dato di quell'oggetto. Per questo motivo dovrebbe essere usato su tutte le funzioni di tipo ispettore (vedi [[appunti3s:programmi_procedurali#classificazione|classificazione delle funzioni]]) Le funzioni di questo tipo sono anche le uniche che possono avere come argomenti interi oggetti costanti come: * const Classe unOggetto * const& Classe unOggetto * const Classe* unOggetto