Abbiamo già incontrato il concetto di overloading (letteralmente "sovraccarico") parlando dei costruttori di una classe. In sostanza è possibile definire più di un costruttore (con lo stesso nome!) per la medesima classe. Il compilatore è in grado di distinguere un costruttore dall'altro in base al numero e/o al tipo di parametri passati.
In C++ l'uso dell'overloading può essere applicato a qualsiasi funzione. Ovvero è possibile ridefinire più volte la stessa funzione con lo stesso nome, purché si usino diversi parametri. Facciamo un esempio. Sappiamo che una delle funzioni della library matematica del C++ è la sqrt per il calcolo della radice quadrata di un numero con la virgola con prototipo:
double sqrt(double);
Supponiamo ora di voler scrivere una funzione per il calcolo della radice quadrata intera di un numero intero, definita come il più grande intero n tale che n*n è minore o uguale al radicando:
In questo modo abbiamo due funzioni con lo stesso nome sqrt: la funzione standard della library matematica e quella definita da noi. Ciò non comporta nessun problema, poiché il compilatore è in grado di stabilire quale funzione deve usare in base al tipo dell'argomento passato: se viene passato un valore double viene usata la funzione di library, se viene passato un int viene usata la funzione scritta da noi.
Si consideri il seguente esempio:
In C++ l'overloading può essere esteso, oltre che alle funzioni, anche agli operatori. In sostanza è possibile ridefinire a piacere il funzionamento di ognuno degli operatori standard, come per esempio +, -, *, /, < , >, == eccetera.
Consideriamo per esempio di nuovo il problema di effettuare la somma di due numeri complessi, precedentemente risolto con una funzione friend di nome somma:
ris = somma(c1, c2);
Sarebbe tuttavia senz'altro più comodo ed elegante poter calcolare la somma fra due numeri complessi in questo modo:
ris = c1 + c2;
La sintassi necessaria per scrivere l'overloading dell'operatore + è molto simile a quella usata in precedenza per la scrittura della funzione somma, come si può notare dal confronto qui sotto:
complex somma(complex n1, complex n2) { complex s; s.a = n1.a + n2.a; s.b = n1.b + n2.b; return s; } |
complex operator+(complex n1, complex n2) { complex s; s.a = n1.a + n2.a; s.b = n1.b + n2.b; return s; } |
Come si vede le due definizioni sono praticamente identiche, a parte l'uso della parola chiave operator seguita dal simbolo dell'operatore che si vuole ridefinire.
Naturalmente affinché l'operatore + abbia diritto di accesso ai campi privati della classe complex, è necessario dichiararlo come friend all'interno della definizione della classe:
Fra i metodi di una classe possono anche essere compresi degli operatori, opportunamente ridefiniti tramite l'overloading. Consideriamo il seguente semplice esempio, mediante il quale viene ridefinito l'operatore ++ di pre-increment:
A questo punto all'interno del programma è possibile usare l'operatore nel seguente modo:
Il risultato dell'esecuzione è ovviamente quello di incrementare di uno sia la parte reale che la parte immaginaria del numero complesso num.
Il codice precedente tuttavia non funziona in un caso un po' più complicato come il seguente:
In questo caso l'assegnazione a num2 produce un errore, dovuto al fatto che l'operatore ++ è stato dichiarato come void (cioè che non torna nessun valore). Per far funzionare il programma bisogna modificare la dichiarazione dell'operatore nel seguente modo:
La parola riservata this del linguaggio C++ indica l'indirizzo della classe di appartenenza (dunque this è un puntatore implicito all'oggetto corrente). L'asterisco davanti (*this) serve per trasformare il puntatore in un'istanza della classe.
Si osservi di passaggio che volendo effettuare l'overloading del postincrement (cioè num++ invece di ++num), la dichiarazione dell'operatore dev'essere la seguente:
Si noti la dichiarazione int fra parentesi tonde che serve appunto per distinguere il post dal preincrement.
Sito realizzato in base al template offerto da
http://www.graphixmania.it