Definizione delle funzioni membro
La definizione dei metodi di una classe puo` essere eseguita o dentro la dichiarazione
di classe, facendo seguire alla lista di argomenti una coppia di parentesi graffe
racchiudente la sequenza di istruzioni:
class Complex {
public:
/* ... */
void Print() {
if (Im >= 0)
cout << Re << " + i" <<
Im;
else
cout << Re << " - i" <<
fabs(Im);
// fabs restituisce il
valore assoluto!
}
private:
/* ... */
};
oppure riportando nella dichiarazione di classe solo il prototipo e definendo
il metodo fuori dalla dichiarazione di classe, nel seguente modo (anch'esso
applicabile alle strutture):
/* Questo modo di procedere richiede l'uso
dell'operatore di risoluzione di scope e l'uso del
nome della classe per indicare esattamente quale
metodo si sta definendo (classi diverse possono
avere metodi con lo stesso nome). */
void Complex::Print() {
if (Im >= 0)
cout << Re << " + i" << Im;
else
cout << Re << " - i" << fabs(Im);
}
I due metodi non sono comunque del tutto identici: nel primo caso implicitamente
si richiede una espansione inline del codice della funzione, nel secondo caso
se si desidera tale accorgimento bisogna utilizzare esplicitamente la keyword
inline nella definizione del metodo:
inline void Complex::Print() {
if (Im >= 0)
cout << Re << " + i" << Im;
else
cout << Re << " - i" << fabs(Im);
}
Se la definizione del metodo Print() e` stata studiata con attenzione,
il lettore avra` notato che la funzione accede ai membri dato senza ricorrere
alla notazione del punto, ma semplicemente nominandoli: quando ci si vuole riferire
ai campi dell'oggetto cui e` stato inviato il messaggio non bisogna adottare
alcuna particolare notazione, lo si fa e basta (i nomi di tutti i membri della
classe sono nello scope di tutti i metodi della stessa classe)!
La domanda corretta da porsi e` come si fa a stabilire dall'interno di un metodo
qual'e` l'effettiva istanza cui ci si riferisce. Il compito di risolvere correttamente
ogni riferimento viene svolto automaticamente dal compilatore: all'atto della
chiamata, ciascun metodo riceve un parametro aggiuntivo, un puntatore all'oggetto
a cui e` stato inviato il messaggio e tramite questo e` possibile risalire all'indirizzo
corretto; cio` inoltre consente la chiamata di un metodo da parte di un altro
metodo:
class MyClass {
public:
void BigOp();
void SmallOp();
private:
void PrivateOp();
/* altre dichiarazioni */
};
/* definizione di SmallOp() e PrivateOp()
*/
void MyClass::BigOp() {
/* ... */
SmallOp(); // questo messaggio
arriva all'oggetto
//
a cui e` stato inviato BigOp()
/* ... */
PrivateOp(); // anche questo!
/* ... */
}
Ovviamente un metodo puo` avere parametri e/o variabili locali che sono istanze
della stessa classe cui appartiene (il nome della classe e` gia` visibile all'interno
della stessa classe), in questo caso per riferirsi ai campi del parametro o
della variabile locale si deve utilizzare la notazione del punto:
class MyClass {
/* ... */
void Func(MyClass A);
};
void MyClass::Func(MyClass A, /* ... */ ) {
/* ... */
BigOp(); // questo messaggio arriva
all'oggetto
// cui e` stato inviato
Func(MyClass)
A.BigOp(); // questo invece arriva al
parametro.
/* ... */
}
In alcuni rari casi puo` essere utile avere accesso al puntatore che il compilatore
aggiunge tra i parametri di un metodo, l'operazione e` fattibile tramite la
keyword this (che in pratica e` il nome del parametro aggiuntivo),
tale pratica quando possibile e` comunque da evitare.
|