Funzioni virtuali

2 febbraio 2012

Le funzioni virtuali sono il meccanismo che ci permette di realizzare il polimorfismo con C++, una delle più importanti caratteristiche dei linguaggi orientati agli oggetti, che permette ad oggetti “simili” di rispondere in modo diverso agli stessi comandi.

In particolare il polimorfismo in C++ si realizza tramite l’overriding delle funzioni

Prendiamo in considerazione un semplice esempio: un insieme di classi che rappresentano dei veicoli a motore: auto, furgone, moto e cosi via. Tutti i veicoli fanno riferimento alla classe base veicolo.

Supponiamo che ogni classe sia dotata di un funzione numRuote che indica il numero di ruote. Indipendentemente dal veicolo, risulterebbe comodo trattare la funzione numRuote come un metodo della classe base veicolo.

In altre parole per sapere quante ruote possiede un certo veicolo non faremmo altro che richiamare la funzione numRuote della classe padre veicolo, sarà poi il compilatore a decidere in maniera automatica a quale classe derivata appartiene la funzione numRuote.

Per ottenere un comportamento di questo tipo, dichiariamo la funzione numRuote della classe base come funzione virtuale e poi la implemetiamo in ogni classe derivata.

Una funzione virtuale si dichiara precedendo il suo prototipo con la parola chiave virtual nella classe base. Per esempio nel nostro caso, nella classe base veicolo comparirà la seguente definizione:

virtual void numRuote() {};

Questa dichiarazione crea una funzione virtuale denominata numRuote(), che non prende ne restituisce alcun valore.

#include <iostream>

using namespace std;

class veicolo
{
  public:
    virtual void numRuote() {};
};

class automobile : public veicolo {
  public:
    void numRuote() { cout << "automobile appartiene a veicolo ed ha 4 ruote" << endl; }
};

class furgone : public veicolo {
  public:
    void numRuote () { cout << "furgone ha 4 ruote" << endl; };
};

class moto : public veicolo {
  public:
    void numRuote () { cout << "moto ha 2 ruote" << endl; };
};


int main()
{
    veicolo* veicoliaMotore[3] = { new automobile, new furgone, new moto };

    for(int i = 0; i < 3; i++)
      veicoliaMotore[i]->numRuote();

    return 0;
}

veicoliaMotore è un vettore di puntatori a oggetti di tipo veicolo, tuttavia nel ciclo for viene invocata la funzione appropriata a seconda dell’oggetto. Grazie a questo meccanismo, qualora venga esteso successivamente il sistema, introducendo un nuovo veicolo derivato, non sarà necessario modificare il ciclo for.

Se si dichiara una funzione come virtuale, essa resta virtuale in tutta la gerarchia dell’ereditarietà dal punto in cui è dichiarata in poi, anche se non è dichiarata virtuale nella ridefinizione operata dalle altre classi.

Sebbene determinate funzioni siano implicitamente virtuali, e ciò per causa di una dichiarazione avvenuta ad un livello superiore nella gerarchia delle classi, è buona norma dichiarare esplicitamente come funzioni virtuali in ogni livello della gerarchia per una maggiore chiarezza e leggibilità del codice.

Infine un po’ di attenzione alla sintassi. Se dichiariamo:

class automobile: veicolo {
  ...
};

poi non possiamo effettuare una dichiarazione simile a questa:

veicolo* a = new automobile();

dovremo utilizzare un cast:

veicolo* a = (veicolo*) automobile();

Per questo definiamo pubblica la dipendenza tra automobile e veicolo:

class automobile: public veicolo {
...
};

Tutte le lezioni

1 ... 51 52 53

Se vuoi aggiornamenti su Funzioni virtuali inserisci la tua e-mail nel box qui sotto:
Tags:
 
X
Se vuoi aggiornamenti su Funzioni virtuali

inserisci la tua e-mail nel box qui sotto:

Ho letto e acconsento l'informativa sulla privacy

Acconsento al trattamento di cui al punto 3 dell'informativa sulla privacy