Come esempio concreto, supponiamo qualcosa del tipo:
class Base
{
...
int some_int;
};
class Derived: public Base
{
...
vector<int> some_vec; // the presence of this field makes 'Derived'
// no longer trivially destructible.
};
Ora se lo facciamo (direttamente come mostrato o indirettamente tramite un puntatore intelligente, ad es.):
Base* base = new Derived;
...
delete base;
... quindi some_vec
non verrà distrutto a meno che Base
definisca un distruttore virtuale. Dopotutto, dato solo un puntatore di base, il sistema non ha le informazioni in fase di runtime per sapere nulla su Derived
a meno che non ci sia una tabella virtuale che punta alle sue funzioni, permettendo che si verifichi un invio dinamico per ottenere informazioni / funzionalità specifiche per Derived
come i suoi requisiti specifici per una distruzione appropriata.
Per eliminare un oggetto tramite un puntatore di base è un comportamento polimorfico, e per farlo in modo sicuro e corretto senza eseguire un comportamento indefinito, la classe base deve definire un distruttore virtuale.
La domanda alla fine si riduce a se si desidera eliminare oggetti tramite un puntatore di base. Se lo fai, quindi definire un distruttore virtuale pubblico:
class BaseSafeDelete
{
public:
// Provides safe destruction through a base pointer.
virtual ~BaseSafeDelete() {}
};
In caso contrario, definire un distruttore non virtuale protetto:
class BaseNoDelete
{
protected:
// Prevents deleting outright through a base pointer.
/*nonvirtual*/ ~BaseNoDelete() {}
};
E, soprattutto, l'eredità è qualcosa da progettare e decidere in anticipo quando si progetta una classe base. Non è adatto come ripensamento per prendere una classe che non è stata progettata per l'ereditarietà (manca un dvd non virtuale protetto o un dvd virtuale pubblico come primo segno) e tenta di estenderla. Per questo, consulta il principio di riutilizzo composito .