====== 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