Overloading

Da Wikipedia, l'enciclopedia libera.
Jump to navigation Jump to search

In programmazione, è detta overloading (o sovraccarico) la creazione di una famiglia di funzioni/subroutine aventi tutte lo stesso nome, ma che accettino un diverso insieme di argomenti (signature), e che eventualmente restituiscano un diverso valore di ritorno (in Java con signature non viene incluso il valore di ritorno). Tale famiglia di funzioni è detta in rapporto di Overloading, o sovraccaricata. Non tutti i linguaggi di programmazione consentono l'overloading.

A seconda dei casi, si può parlare di overloading di funzioni, di costruttori e di operatori. Sovraccaricare il costruttore di una classe è una pratica comune per gli sviluppatori di librerie, in quanto permette loro di fornire allo sviluppatore finale diverse modalità per istanziare inizializzando l'oggetto della classe con determinati valori iniziali.

Overloading del costruttore e dei metodi delle classimodifica | modifica wikitesto

Ecco alcuni esempi di sovraccarico di un costruttore "Persona" e un metodo "Rubrica.Inserisci", in linguaggio Visual Basic (è omessa la dichiarazione di un tipo enumerativo "Sesso" di valore "Maschio/Femmina" e di alcune implementazioni)

Class Persona

Private _nome As String
Private _cognome As String
Private _nascita As Date
Private _sex As Sesso

Public ReadOnly Property NomeCompleto() As String

Public Sub New(ByVal nome As String, ByVal cognome As String, ByVal nascita As Date, ByVal sex As Sesso)
    _nome = nome
    _cognome = cognome
    _nascita = nascita
    _sex = sex
End Sub

Public Sub New(ByVal AltraPersona As Persona)
    _nome = altrapersona._nome
    _cognome = altrapersona._cognome
    _nascita = altrapersona._nascita
    _sex = altrapersona._sex
End Sub
End Class

Class Rubrica
...
Public Overloads Sub Inserisci(ByVal Nome As String, ByVal Cognome As String)
Public Overloads Sub Inserisci(ByVal Item As Persona)
End Class

In questo modo è possibile inizializzare un'istanza della classe Persona sia fornendo nome e cognome come stringa che copiandoli da un'altra istanza di Persona. Il codice di cui sopra è facilmente riutilizzabile in linguaggi come C, C++, C# e Java, riscrivendo il tutto secondo la sintassi del linguaggio scelto.

Overloading degli operatorimodifica | modifica wikitesto

Prendiamo in considerazione il seguente esempio C++: una classe che rappresenta i numeri complessi (sono omesse le implementazioni del file .cpp)

class Complex
{
private:
    double _r;
    double _i;

public:
    Complex(int r, int i);
    Complex(float r, float i);
    Complex(double r, double i);
    Complex(Complex c);
}

Vorremmo essere in grado di eseguire sui numeri complessi le stesse operazioni che eseguiamo normalmente sui numeri reali. Ad esempio, vorremmo poter eseguire il seguente codice:

Complex c,d;
...
if (c < d)
    ....
...
cout << c;

Tale codice solleverebbe un errore di compilazione, in quanto il compilatore non è in grado di valutare da solo se il complesso c è minore di d, né tantomeno di scriverlo a video. La soluzione, adottabile solo in C++ e C#, è quella di definire un opportuno sovraccarico per gli operatori < e <<. Per fare ciò è necessario conoscere come il compilatore dei linguaggi C tratta le espressioni con operatore. Esso le traduce con una chiamata a subroutine operator?(), dove al posto di ? va il simbolo dell'operatore. Ecco quindi i prototipi (e un paio di realizzazioni) di una completa famiglia di overloading per gli operatori principali di confronto e output.

//operator<
int operator<(Complex a, Complex b)
{
    return ((a.r*a.r+a.i*a.i)<(b.r*b.r+b.i*b.i));
}

int operator<(Complex a, double b)
{
    return ((a.r*a.r+a.i*a.i)<(b*b));
}

int operator<(Complex a, float b);
int operator<(Complex a, int b);
int operator<(double a, Complex b);
int operator<(float a, Complex b);
int operator<(int a, Complex b);
 
//operator>
int operator>(Complex a, Complex b)
{
   return ((a.r*a.r+a.i*a.i)>(b.r*b.r+b.i*b.i));
}

int operator>(Complex a, double b)
{
    return ((a.r*a.r+a.i*a.i)>b*b);
}

int operator>(Complex a, float b);
int operator>(Complex a, int b);
int operator>(double a, Complex b);
int operator>(float a, Complex b);
int operator>(int a, Complex b);

//operator<<
ostream& operator<<(ostream& out, Complex c)
{
    cout << c.r;
    if (c.i > 0)
        cout << "+";
    cout << c.i << "i";
}

In linguaggio Visual Basic è possibile simulare il sovraccarico degli operatori implementando l'interfaccia IComparable.

Note sull'overloadingmodifica | modifica wikitesto

Un errore comune di molti programmatori è quello di voler creare due funzioni che accettano gli stessi tipi di parametri in ingresso e restituiscono un tipo differente. Ciò non è possibile perché l'esecutore identifica le funzioni e le subroutine, a livello assembly, mediante delle etichette (label). Tali label rispecchiano la signature della funzione stessa, e pertanto due label uguali non possono coesistere all'interno di uno stesso spazio di visibilità. È comunque possibile definire due o più funzioni dalla stessa signature all'interno di spazi di nomi diversi senza ottenere errori di compilazione.

L'overloading, infine, non influisce sulla corretta esecuzione delle procedure ricorsive.

Voci correlatemodifica | modifica wikitesto