Ho una solida comprensione della maggior parte della teoria OO, ma una cosa che mi confonde molto sono i distruttori virtuali.
Pensavo che il distruttore venisse sempre chiamato, non importa cosa e per ogni oggetto nella catena.
Quando bisogna renderli virtuali e perché?
I distruttori virtuali sono utili quando potreste potenzialmente cancellare un'istanza di una classe derivata attraverso un puntatore alla classe base:
class Base
{
// some virtual methods
};
class Derived : public Base
{
~Derived()
{
// Do some important cleanup
}
};
Qui, noterete che non ho dichiarato il distruttore di Base come "virtuale". Ora, diamo un'occhiata al seguente snippet:
Base *b = new Derived();
// use b
delete b; // Here's the problem!
Poiché il distruttore di Base non è virtuale
e b
è un Base*
che punta ad un oggetto Derivato
, delete b
ha un comportamento non definito:
[In delete b
], se il tipo statico dell'oggetto
oggetto da cancellare è diverso dal suo tipo dinamico, il tipo statico
deve essere una classe base del tipo dinamico dell'oggetto da
cancellato e il tipo statico deve avere un distruttore virtuale o il
comportamento è indefinito.
Nella maggior parte delle implementazioni, la chiamata al distruttore sarà risolta come qualsiasi codice non virtuale, il che significa che il distruttore della classe base sarà chiamato ma non quello della classe derivata, con conseguente perdita di risorse.
Per riassumere, rendete sempre le classi base "virtuali" quando sono destinate ad essere manipolate polimorficamente.
Se volete impedire la cancellazione di un'istanza attraverso un puntatore di classe base, potete rendere il distruttore della classe base protetto e non virtuale; così facendo, il compilatore non vi permetterà di chiamare delete
su un puntatore di classe base.
Potete imparare di più sulla virtualità e sul distruttore virtuale della classe base in questo articolo di Herb Sutter.
Dichiarare i distruttori virtuali nelle classi base polimorfe. Questo è il punto 7 in Scott Meyers' Effective C++. Meyers continua a riassumere che se una classe ha qualsiasi funzione virtuale, dovrebbe avere un distruttore virtuale, e che le classi non progettate per essere classi base o non progettate per essere usate polimorficamente dovrebbero non dichiarare distruttori virtuali.