back to top

L’overloading degli operatori in C++

All’atto della scrittura di un programma, anche molto semplice, ci si ritrova spesso a fare uso di funzioni. Per funzione si intende una parte di codice identificata da un nome e da una serie di parametri, che può essere richiamata in varie parti del programma.

Grazie all’utilizzo di funzioni una stessa porzione di codice, utilizzata in più parti del programma, non deve essere riscritta più volte: sarà infatti possibile scrivere la parte di codice in comune all’interno di una funzione che potrà essere richiamata quando necessario.

Ad esempio si potrebbe definire una funzione stampa che visualizzi a video un certo numero di parametri di interesse e richiamarla poi con una semplice riga di codice (il nome della funzione) ogni volta che, nel programma principale, sia necessario avviare la visualizzazione di tali dati. Si migliora in tal modo sia l’efficienza nella programmazione sia la leggibilità del codice.

Poniamo il caso però che si abbia a che fare con situazioni in cui si richiedono funzioni con funzionalità analoghe ma formalmente diverse.

Riprendiamo l’esempio già esposto in precedenza: supponiamo che la nostra ipotetica funzione di stampa abbia lo scopo di stampare a video tutti i records estratti da una data tabella del nostro database; si ipotizzi, ancora, che in talune altre circostanza si desideri estrarre solo un numero determinato di records.

La soluzione più immediata sarebbe, senz’altro, quella di scrivere due funzioni distinte, caratterizzate dunque da nomi diversi. Tale scelta non risulta però brillante dal punto di vista della leggibilità del codice, considerando che entrambe le funzioni svolgono, a livello concettuale, un ruolo del tutto analogo (estrarre dati dal database).

Sarebbe possibile anche sviluppare un’unica funzione in grado di diversificare il proprio operato sulla base da due numeri interi passati in argomento: il primo indicherebbe il tipo di lavoro da svolgere (ad esempio 0 per stampare l’intera tabella, 1 per stamparne una parte) ed il secondo il numero di righe da stampare in caso si stampi una parte della tabella (in caso contrario il valore del secondo parametro sarebbe ininfluente). Da un punto di vista funzionale questa soluzione è ineccepibile, ma da un punto di vista logico credo sia una soluzione concettualmente debole in quanto si ricorre a parametri fittizi e non necessari.

Allora perchè invece non sviluppare due funzioni identificate dallo stesso nome, una senza parametri (stampa l’intera tabella) e una con un parametro intero (stampa un certo numero di righe)?

Tale possibilità è garantita dal meccanismo di overloading, che consente di derogare alla regola secondo cui una funzione debba essere identificata da un nome univoco, garantendo la possibilità di distinguere a quale delle omonime funzioni debba farsi ricorso semplicemente facendo riferimento al numero ed alla tipologia di parametri forniti.

Ad esempio ipotizziamo di scrivere un codice che contenga le seguenti definizioni di funzione:

int somma(int addendo1,int addendo2)
int somma(int addendo1,int addendo2,int addendo3)
E’ possibile definire separatamente il corpo delle due funzioni e richiamare quella più opportuna con una chiamata a somma accompagnata da due parametri interi per la prima funzione, tre per la seconda.

Definito in generale il meccanismo di overloading, è interessante notare come il linguaggio C++ offra un’ulteriore interessante opportunità: l’overloading degli operatori.

E’ possibile cioè associare all’utilizzo di un operatore, se legato ad operazioni relative ad una certa classe, una particolare sequenza di istruzioni definita nel corpo della classe stessa.

Ad esempio, se si volesse progettare una classe Counter con funzioni di contatore potrebbe essere utile (oltre alla definizione, ad esempio, dei costruttori, del distruttore, del costruttore di copia e di un metodo per incrementare il valore del dato membro della classe) anche far sì che tale incremento possa essere realizzato tramite l’uso dell’operatore unario ++. In altre parole si vuol rendere possibile e corretta, nel programma principale, una sequenza del tipo:

Counter count=new Counter(0);
count++;
con corrispondente incremento del valore del dato membro val di count.

Per ottenere tale risultato è necessario dichiarare all’interno dei metodi della classe Counter un particolare metodo denominato, in questo caso, void operator++, ad esempio in questo modo:

class Counter{
unsigned short val;
...
public:
...
void operator++()
}
A livello di implementazione, seguirà la descrizione delle azioni da associare all’operatore ++:
void Counter::operator++()
{
val++;
}
L’overloading degli operatori risulta utile soprattutto nel caso in cui l’utilizzo di un operatore risulti particolarmente intuitivo per un’operazione di uso comune tra oggetti del tipo che si sta definendo in fase di progettazione della classe (ad esempio può essere di grande praticità l’overloading dell’operatore binario + per la concatenazione di stringhe di testo o simile).

Questa possibilità è utile anche qualora si desideri sovraccaricare gli operatori matematici al fine di mantenere il loro significato comune anche in contesti matematici differenti. Si pensi, ad esempio, all’utilizzo dell’operatore + per lavorare con i vettori (si pensi, per semplicità, a vettori costituiti da due soli elementi), utilizzo che può essere opportunamente ridefinito grazie all’overloading, facendo sì che la somma di due vettori abbia come risultato un vettore con componenti uguali ciascuna alla somma delle componenti dei due addendi. Ad esempio:

class Vector{
int x;
int y;
...
public:
...
Vector operator +(Vector v);
}
...
Vector Vector::operator +(Vector v)
{
Vector temp=new Vector();
temp.x=this.x+v.getx();
temp.y=this.y+v.gety();
return temp;
}

Pubblicitร 

Leggi anche...

Radice quadrata in C: vediamo come calcolarla in diversi modi

La radice quadrata è un'operazione matematica piuttosto comune (in...

Sperimentare la sequenza di Collatz in C++

Vediamo come verificare la congettura di Collatz con C++....

Calcolare la radice quadrata con Python

In Python è possibile calcolare la radice quadrata usando...

12 film che ogni programmatore dovrebbe guardare (per trovare ispirazione e creatività)

Molti ragazzi hanno deciso di intraprendere una carriera da...

Cartonizzare una foto con Python e la libreria OpenCV

La cartoonization è una procedura grafica che consente di...

Creare flowchart (diagrammi di flusso) online: 5 strumenti gratuiti

Hai bisogno di realizzare una flow chart ma non...
Pubblicitร