domenica 30 dicembre 2012

Definire funzioni membro virtuali

Un oggetto di una classe derivata è anche un membro di una classe di base. Per esempio, il programma Capo virtuale, l'oggetto Capo è anche un oggetto Nemico. Tutto ciò ha senso in quando si tratta solo di un tipo di nemico speciale. Inoltre ha senso in quanto l'oggetto Capo ha tutti i membri dell'oggetto Nemico. Bene, e allora? Poiché una classe derivata è anche un membro della classe di base, si può usare un puntatore alla classe di base per puntare un oggetto della classe derivata. Questo è ciò che faccio in main() con la seguente istruzione, la quale istanzia un oggetto Capo su heap e crea un puntatore a Nemico che punti all'oggetto Capo.
Nemico* pCattivo = new Capo();

Cosa vuol dire tutto questo? E' utile a permetterci di gestire l'oggetto senza doverne conoscere il tipo esatto. Per esempio di può avere una funzione che accetta un puntatore a Nemico e può funzionare sia con Nemico che con Capo oggetti. La funzione non deve conoscere l'esatta tipologia di oggetto passato, può funzionare con oggetti che producono risultati diversi a seconda di quale sia utilizzato. Ma ora analizziamo cosa accade nella successiva riga di codice.
pCattivo - > Fastidio();

Invece mostra una linea di testo Il nemico vuole combatterti. Quindi non è stata richiamata la funzione Fastidio() dell'oggetto Capo ma dell'oggetto Nemico, nonostante sia stata superata dalla funzione Fastidio() nella classe di Capo. Questo accade come risultato di un legame precedente nel quale l'esatta funzione è legata al tipo di puntatore, in questo caso Nemico. Ciò di cui si ha bisogno è una funzione membro chiamata sul tipo di oggetto puntato, e non fissato dal puntatore. In questo si ottiene la flessibilità del legame successivo attraverso funzioni virtuali, che ottiene con il comportamento polimorfico. Per creare una funzione membro virtuale, si aggiunge semplicemente la parola chiave virtual prima del nome della funzione nella sua dichiarazione. Questo è ciò che viene fatto in Nemico con la seguente istruzione.
void virtual VFastidio() const
{ cout << “Il nemico vuole combatterti.\n”; }

Questo significa che VFastidio() è una funzione virtuale. E' virtuale in Nemico, e viene ereditata in Capo. Questo impila che VFastidio() in Capo possa superare con la seguente istruzione la funzione ereditata. La corretta versione di VFastidio() viene chiamata (in base al tipo di oggetto) e non sarà fissata dal tipo di puntatore.
void virtual VFastidio() const
{ cout << “Il capo vuole mettere fine alla tua esistenza.\n”; }

La prova del comportamento polimorfico viene in main() con la seguente istruzione, nel quale la funzione VFastidio() definita in Capo viene chiamata ed il testo “Il capo vuole mettere fine alla tua esistenza”. Viene mostrato su schermo.

pCattivo - > VFastidio();

Definire Distruttori virtuali

Quando si usa un puntatore alla classe di base per puntare un oggetto di una classe derivata, si può avere un potenziale problema. Quando viene cancellato il puntatore, solo il distruttore della classe viene chiamato per l'oggetto. Questo può condurre a risultati disastrosi poiché il distruttore della classe derivata è necessario per liberare la memoria ( come fa il distruttore di Capo). La soluzione come si può indovinare, è di rendere il distruttore della classe virtuale. In questo modo viene chiamato il distruttore della classe, il qual conduce (sempre) alla chiamata del distruttore della classe di base, dando ad ogni classe la possibilità di ripulirsi. La teoria viene messa in pratica quando si crea il distruttore virtuale della classe Nemico.
virtual ~Nemico(){ cout << “m_pDanno cancellato”; delete m_pDanno;}
Quando viene cancellato il puntatore che punta alla classe Capo con la seguente istruzione, il distruttore della classe Capo viene chiamato, il quale libera la memoria su heap dei dati m_pMultidanno e mostra il messaggio.
delete pCattivo;

Quindi viene chiamato il distruttore di Nemico, il quale libera la memoria su heap da m_pDanno e mostra il messaggio m_pDanno cancellato. L'oggetto è distrutto, e tutte le memorie associate ad esso sono cancellate.

Nessun commento:

Posta un commento