I distruttori virtuali sono utili quando si potrebbe potenzialmente eliminare 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 noterai che non ho dichiarato il distruttore di Base virtual
. Ora diamo un'occhiata al seguente frammento:
Base *b = new Derived();
// use b
delete b; // Here's the problem!
Poiché il distruttore di Base non è virtual
ed b
è un Base*
puntamento a un Derived
oggetto, delete b
ha un comportamento indefinito :
[In delete b
], se il tipo statico dell'oggetto da eliminare è diverso dal suo tipo dinamico, il tipo statico deve essere una classe base del tipo dinamico dell'oggetto da eliminare e il tipo statico deve avere un distruttore virtuale o il comportamento non è definito .
Nella maggior parte delle implementazioni, la chiamata al distruttore verrà risolta come qualsiasi codice non virtuale, il che significa che verrà chiamato il distruttore della classe base ma non quello della classe derivata, con conseguente perdita di risorse.
Per riassumere, crea sempre i distruttori delle classi di base virtual
quando devono essere manipolati polimorficamente.
Se si desidera impedire la cancellazione di un'istanza tramite un puntatore della classe base, è possibile rendere il distruttore della classe base protetto e non virtuale; così facendo, il compilatore non ti permetterà di chiamare delete
un puntatore della classe base.
Puoi saperne di più sulla virtualità e sul distruttore di classe di base virtuale in questo articolo da Herb Sutter .