C ++ Distruttori virtuali utilizzati solo quando ci sono funzioni virtuali

2

Questo è da Effective C ++ (Meyers):

Classes not designed to be base classes or not designed to be used polymorphically should not declare virtual destructors

Non capisco perché le classi non polimorfiche non dovrebbero dichiarare i distruttori virtuali.

Supponendo che io abbia una classe genitore e una classe figlia, senza funzioni virtuali, e ho un puntatore classe-genitore su un oggetto figlio: se chiamo delete sul puntatore classe-genitore, chiamerà solo distruttore genitore, anche se voglio chiamare anche il distruttore figlio.

    
posta manlio 12.01.2016 - 17:42
fonte

3 risposte

4

Assuming I have a parent class and a child class, with no virtual functions, and I have a parent-class-pointer to a child object

Quindi lo stai usando in modo polimorfico.

Anche se non vedo molto nel farlo. Senza membri virtuali, la sottoclasse non ha molte opportunità di influenzare il comportamento del programma rispetto all'uso della sola classe base.

Una classe non polimorfica è quella che non può essere usata per puntare a oggetti di classi derivate. Queste sono o classi che non saranno derivate (che in C ++ è per la maggior parte!) O classi che sono utilizzate come base per il riutilizzo del codice senza fornire un'interfaccia completa per qualsiasi cosa (ad esempio std::iterator ; è una classe di base pubblica della maggior parte degli iteratori, ma non ha senso creare un std::iterator * ).

    
risposta data 13.01.2016 - 10:22
fonte
4

La parola chiave qui è non progettata

Classes not designed to be base classes or not designed to be used polymorphically

Le funzioni virtuali / distruttori non sono gratuite: causano un sovraccarico delle prestazioni, quindi potresti non volerle usare in tutti i casi. Tuttavia, l'eliminazione di un oggetto classe derivato utilizzando un puntatore a una classe base con un distruttore non virtuale ha come risultato un comportamento non definito:

link

Questo è il compromesso tra prestazioni e sicurezza.

    
risposta data 13.01.2016 - 05:11
fonte
1

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 .

    
risposta data 13.01.2016 - 12:05
fonte

Leggi altre domande sui tag