1935 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?

2voto

user2641018 Punkte 108

Wenn Sie den Destruktor einer abgeleiteten Klasse von der Basisklasse aus aufrufen müssen, müssen Sie den virtuellen Destruktor der Basisklasse in der Basisklasse deklarieren.

1voto

Ted Shaneyfelt Punkte 635

Machen Sie alle Destruktoren virtuell, es sei denn, Sie haben gute Gründe, dies nicht zu tun.

Sonst passiert so etwas Böses:

Angenommen, Sie haben ein Array von Fruit-Zeigern mit den beiden Objekten Apple und Orange.

Wenn Sie aus der Sammlung von Fruit-Objekten löschen, ~Apple() und ~Orange() werden nicht aufgerufen, es sei denn, ~Fruit() ist virtuell.

Richtig gemachtes Beispiel:

#include <iostream>
using namespace std;
struct Fruit { // good
  virtual ~Fruit() { cout << "peel or core should have been tossed" << endl; } 
};
struct Apple:  Fruit { virtual ~Apple()  {cout << "toss core" << endl; } };
struct Orange: Fruit { virtual ~Orange() {cout << "toss peel" << endl; } };

int main() { 
  Fruit *basket[]={ new Apple(), new Orange() };
  for (auto fruit: basket) delete fruit;
};

gute Leistung

toss core
peel or core should have been tossed
toss peel
peel or core should have been tossed

Beispiel falsch gemacht:

#include <iostream>
using namespace std;
struct Fruit { // bad 
  ~Fruit() { cout << "peel or core should have been tossed" << endl; } 
};
struct Apple:  Fruit { virtual ~Apple()  {cout << "toss core" << endl; } };
struct Orange: Fruit { virtual ~Orange() {cout << "toss peel" << endl; } };

int main() { 
  Fruit *basket[]={ new Apple(), new Orange() };
  for (auto fruit: basket) delete fruit;
};

schlechte Leistung

peel or core should have been tossed
peel or core should have been tossed

(Hinweis: Wo ich der Einfachheit halber struct verwendet habe, verwende ich normalerweise class und gebe public an)

0voto

rekkalmd Punkte 143

Eine grundlegende Definition über virtual ist, dass sie bestimmt, ob eine Mitgliedsfunktion einer Klasse in ihren abgeleiteten Klassen überschrieben werden kann.

Der D-Tor einer Klasse wird grundsätzlich am Ende des Geltungsbereichs aufgerufen, aber es gibt ein Problem, zum Beispiel, wenn wir eine Instanz auf dem Heap (dynamische Zuweisung) definieren, sollten wir sie manuell löschen.

Sobald die Anweisung ausgeführt wird, wird der Destruktor der Basisklasse aufgerufen, nicht aber der der abgeleiteten Klasse.

Ein praktisches Beispiel ist, wenn Sie im Bereich der Steuerung Effektoren und Aktoren manipulieren müssen.

Wenn am Ende des Anwendungsbereichs der Destruktor eines der Leistungselemente (Actuator) nicht aufgerufen wird, hat das fatale Folgen.

#include <iostream>

class Mother{

public:

    Mother(){

          std::cout<<"Mother Ctor"<<std::endl;
    }

    virtual~Mother(){

        std::cout<<"Mother D-tor"<<std::endl;
    }

};

class Child: public Mother{

    public:

    Child(){

        std::cout<<"Child C-tor"<<std::endl;
    }

    ~Child(){

         std::cout<<"Child D-tor"<<std::endl;
    }
};

int main()
{

    Mother *c = new Child();
    delete c;

    return 0;
}

-1voto

Syed H Punkte 195

Jede Klasse, die öffentlich vererbt wird, ob polymorph oder nicht, sollte einen virtuellen Destruktor haben. Anders ausgedrückt: Wenn ein Zeiger der Basisklasse auf sie verweisen kann, sollte ihre Basisklasse einen virtuellen Destruktor haben.

Wenn sie virtuell ist, wird der Destruktor der abgeleiteten Klasse aufgerufen und dann der Destruktor der Basisklasse. Wenn nicht virtuell, wird nur der Destruktor der Basisklasse aufgerufen.

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