1895 Stimmen

Wann sollten virtuelle Destruktoren verwendet werden?

Ich habe ein solides Verständnis der meisten OOP Theorie, aber die eine Sache, die mich sehr verwirrt, sind virtuelle Zerstörer.

Ich dachte, dass der Destruktor immer aufgerufen wird, egal was und für jedes Objekt in der Kette.

Wann sollen Sie sie virtuell machen und warum?

1930voto

Luc Touraille Punkte 76149

Virtuelle Destruktoren sind nützlich, wenn Sie möglicherweise eine Instanz einer abgeleiteten Klasse durch einen Zeiger auf die Basisklasse löschen können:

class Base 
{
    // some virtual methods
};

class Derived : public Base
{
    ~Derived()
    {
        // Do some important cleanup
    }
};

Hier werden Sie feststellen, dass ich den Destruktor von Base nicht als virtual . Schauen wir uns nun den folgenden Ausschnitt an:

Base *b = new Derived();
// use b
delete b; // Here's the problem!

Da der Destruktor von Base nicht virtual y b ist eine Base* und zeigt auf eine Derived Objekt, delete b hat undefiniertes Verhalten :

[In delete b ], wenn der statische Typ des zu löschenden Objekts von seinem dynamischen Typ abweicht, wird der statische Typ eine Basisklasse des dynamischen Typs des zu löschenden Objekts sein zu löschenden Objekts und der statische Typ muss einen virtuellen Destruktor haben oder das Verhalten ist undefiniert .

In den meisten Implementierungen wird der Aufruf des Destruktors wie jeder nicht-virtuelle Code aufgelöst, was bedeutet, dass der Destruktor der Basisklasse aufgerufen wird, nicht aber der der abgeleiteten Klasse, was zu einem Ressourcenleck führt.

Zusammenfassend lässt sich sagen, dass die Destruktoren der Basisklassen immer virtual wenn sie für polymorphe Manipulationen gedacht sind.

Wenn Sie das Löschen einer Instanz durch einen Basisklassenzeiger verhindern wollen, können Sie den Destruktor der Basisklasse geschützt und nicht-virtuell machen; dadurch lässt der Compiler den Aufruf von delete auf einen Zeiger einer Basisklasse.

Mehr über Virtualität und den Destruktor der virtuellen Basisklasse erfahren Sie in dieser Artikel von Herb Sutter .

319voto

Ein virtueller Konstruktor ist nicht möglich, aber ein virtueller Destruktor ist möglich. Lassen Sie uns experimentieren.......

#include <iostream>

using namespace std;

class Base
{
public:
    Base(){
        cout << "Base Constructor Called\n";
    }
    ~Base(){
        cout << "Base Destructor called\n";
    }
};

class Derived1: public Base
{
public:
    Derived1(){
        cout << "Derived constructor called\n";
    }
    ~Derived1(){
        cout << "Derived destructor called\n";
    }
};

int main()
{
    Base *b = new Derived1();
    delete b;
}

Der obige Code gibt das Folgende aus:

Base Constructor Called
Derived constructor called
Base Destructor called

Die Konstruktion des abgeleiteten Objekts folgt der Konstruktionsregel, aber wenn wir den "b"-Zeiger (Basiszeiger) löschen, haben wir festgestellt, dass nur der Basisdestruktor aufgerufen wird. Das darf aber nicht passieren. Um das Richtige zu tun, müssen wir den Basisdestruktor virtuell machen. Sehen wir uns nun an, was im Folgenden geschieht:

#include <iostream>

using namespace std;

class Base
{ 
public:
    Base(){
        cout << "Base Constructor Called\n";
    }
    virtual ~Base(){
        cout << "Base Destructor called\n";
    }
};

class Derived1: public Base
{
public:
    Derived1(){
        cout << "Derived constructor called\n";
    }
    ~Derived1(){
        cout << "Derived destructor called\n";
    }
};

int main()
{
    Base *b = new Derived1();
    delete b;
}

Die Ausgabe hat sich wie folgt geändert:

Base Constructor Called
Derived Constructor called
Derived destructor called
Base destructor called

Die Zerstörung des Basiszeigers (die eine Zuweisung auf das abgeleitete Objekt erfordert!) folgt also der Zerstörungsregel, d.h. erst das abgeleitete, dann das Basisobjekt. Auf der anderen Seite gibt es nichts wie einen virtuellen Konstruktor.

223voto

Bill the Lizard Punkte 384619

Destruktoren in polymorphen Basisklassen als virtuell deklarieren. Dies ist Punkt 7 in Scott Meyers' Wirksames C++ . Meyers fasst weiter zusammen, dass eine Klasse, die jede virtuellen Funktion einen virtuellen Destruktor haben sollte, und dass Klassen, die nicht als Basisklassen oder für eine polymorphe Verwendung konzipiert sind, eine no virtuelle Destruktoren deklarieren.

49voto

yesraaj Punkte 44150

Machen Sie den Destruktor virtuell, wenn Ihre Klasse polymorph ist.

49voto

BigSandwich Punkte 2668

Beachten Sie auch, dass das Löschen eines Basisklassenzeigers, wenn es keinen virtuellen Destruktor gibt, dazu führt, dass undefiniertes Verhalten . Etwas, das ich erst kürzlich gelernt habe:

Wie sollte sich die Überschreibung von delete in C++ verhalten?

Ich benutze C++ schon seit Jahren und schaffe es immer noch, mich zu erhängen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X