Virtueller Destruktor in C++

Virtueller Destruktor In C



C++ ist die Sprache, die verwendet wird, um das Grundkonzept der Programmierung zu vertiefen und das logische Denken der Programmierer zu stärken. In C++ spielt OOP eine wichtige Rolle, da OOP eine objektorientierte Sprache ist, die die Objekte von Klassen erstellt. In OOP untersuchen wir die Klassen und Objekte. Klassen enthalten die Datenelemente, die Variablen verschiedener Typen und verschiedene Elementfunktionen sind. Mit Hilfe von Instanzen greifen wir auf die Daten beliebiger Klassen zu. Jede Klasse hat ihren Konstruktor und Destruktor, wenn Sie die Klasse erstellen. Der Konstruktor wird selbst aufgerufen, wenn das Objekt dieser Klasse erstellt wird. Wir können die Variablen einer Klasse auch innerhalb des Konstruktors initialisieren. Destruktoren werden ebenfalls automatisch mit dem Konstruktor erstellt, aber Destruktoren zerstören das Objekt und es ist die letzte Funktion, die aufgerufen wird, bevor das Objekt zerstört wird. Der Name der Klasse, zum Beispiel die Klasse „Beruf“, wird erstellt. Sein Konstruktor ist Profession() und der Destruktor ist ~Profession(). Alle drei haben den gleichen Namen.

Nachdem wir über OOP, Konstruktoren und Destruktoren gesprochen haben, sprechen wir nun über virtuelle Destruktoren. Die virtuellen Destruktoren zerstören, wie der Name schon sagt, das Objekt. Wir haben eine Basisklasse und eine abgeleitete Klasse, die von der Basisklasse abgeleitet ist. Beide Klassen haben ihre Konstruktoren und Destruktoren. Der virtuelle Destruktor gibt Reminiszenzen frei, die durch das abgeleitete Klassenobjekt zugewiesen wurden, während er die Objekte der abgeleiteten Klasse unter Verwendung eines Basisklassenzeigers mit dem Schlüsselwort „virtual“ löscht.

Warum verwenden wir den virtuellen Destruktor?

Wenn die Ausführung der Klassenmemberfunktionen abgeschlossen ist oder die Ausführung der main()-Methode kurz vor dem Ende steht, wird der Destruktor automatisch aufgerufen, um den Speicher freizugeben, der während der Objekterstellung zugewiesen wurde. Warum verwenden wir nun einen virtuellen Destruktor? Wenn die Basisklasse gelöscht wird, die auf die abgeleitete Klasse zeigt, wird hier der Zeiger (*) verwendet. Der Destruktor der Basisklasse wird nur während dieses Prozesses aufgerufen. Der Destruktor der abgeleiteten Klasse wird nicht aufgerufen, was zu Problemen führt. Eines davon ist ein Problem mit Speicherlecks. Um dieses Problem zu vermeiden und unseren Code sicher zu machen, zerstören wir die Objekte virtuell, um den Speicherplatz freizugeben, der während der Erstellung von Objekten zugewiesen wurde, indem wir den Destruktor der Basisklasse löschen.

Einfaches C++-Beispiel ohne virtuellen Destruktor

Mal sehen, wie das Programm ohne virtuellen Destruktor mit einem einfachen Programm funktioniert, das den Zeiger löscht.

Code:

#include

mit Namensraum std ;
Klasse Parent_Class0
{
Öffentlichkeit :
Parent_Class0 ( )
{ cout << 'Konstrukteur der übergeordneten Klasse' << Ende ; }
~Eltern_Klasse0 ( )
{ cout << 'Übergeordneter Klassenzerstörer' << Ende ; }
} ;
Klasse Kind_1 : öffentlich Parent_Class0
{
Öffentlichkeit :
Kind_1 ( )
{ cout << 'Konstrukteur der Kinderklasse' << Ende ; }
~Kind_1 ( )
{ cout << 'Untergeordneter Klassenzerstörer' << Ende ; }
} ;
int hauptsächlich ( )
{
Parent_Class0 * Zeiger = neues Kind_1 ( ) ;
Zeiger löschen ;
Rückkehr 0 ;
}

Dieser Code erklärt, wie der Code ohne einen virtuellen Destruktor ausgeführt wird. Erstellen Sie zunächst eine Klasse namens „Parent_Class0“, die die übergeordnete Klasse sein wird. Erstellen Sie innerhalb dieser Klasse einen Konstruktor und einen Destruktor. Wie wir wissen, heißen Konstruktor und Destruktor genauso wie die Klasse. Der Destruktor wird ähnlich wie der Konstruktor dargestellt, hat aber ein Symbol (~), das ihn vom Konstruktor unterscheidet. Geben Sie innerhalb des Konstruktors und des Destruktors eine Nachricht mit „cout<<“ aus. Erstellen Sie nun eine weitere Klasse namens „Child_1“. Diese Klasse wird von der übergeordneten Klasse „Parent_Class0“ abgeleitet. Die abgeleitete Klasse hat ihren Konstruktor und Destruktor, die eine Meldung enthalten, die auf dem Ausgabebildschirm ausgegeben werden soll.

In der Methode main() erzeugen wir eine Instanz der „Parent_Class0“ und weisen ihr eine abgeleitete Klasse zu. Der entscheidende Punkt, an den Sie sich in diesem Fall erinnern müssen, ist, dass wir einen Zeiger verwenden, um die übergeordnete Klasse abzurufen. Wenn es in die übergeordnete Klasse geht, führt es den Konstruktor der übergeordneten Klasse aus. Dann geht es zur untergeordneten Klasse und führt ihren Konstruktor aus. Bevor der Destruktor der untergeordneten Klasse ausgeführt wird, muss der Destruktor der übergeordneten Klasse ausgeführt werden. Der Compiler führt den Destruktor der übergeordneten Klasse aus und beendet die Klasse, ohne den Destruktor einer untergeordneten Klasse auszuführen. Das ist das Problem; es befreit nicht die Erinnerung an die Klasse des Kindes. Es repräsentiert den Konstruktor einer übergeordneten Klasse, den Konstruktor einer untergeordneten Klasse und den Destruktor einer übergeordneten Klasse. Das zeigt, dass der Destruktor einer untergeordneten Klasse nicht ausgeführt wird. Nach dieser Ausführung löschen wir den Zeiger in der Funktion main().

Ausgabe:

C++-Beispiel mit virtuellem Destruktor

Lassen Sie uns den virtuellen Destruktor mit einem einfachen Code besprechen, um zu unterscheiden, wie er mit und ohne virtuellen Destruktor funktioniert.

Code:

#include

mit Namensraum std ;
Klasse Parent_Class0
{
Öffentlichkeit :
Parent_Class0 ( )
{ cout << 'Konstrukteur der übergeordneten Klasse' << Ende ; }
virtuelles ~Parent_Class0 ( )
{ cout << 'Übergeordneter Klassenzerstörer' << endl ; }
} ;
Klasse Kind_1 : öffentlich Parent_Class0
{
Öffentlichkeit :
Kind_1 ( )
{ cout << 'Konstrukteur der Kinderklasse' << endl ; }
virtuelles ~Kind_1 ( )
{ cout << 'Untergeordneter Klassenzerstörer' << Ende ; }
} ;
int hauptsächlich ( )
{
Parent_Class0 * Zeiger = neues Kind_1 ( ) ;
Zeiger löschen ;
Rückkehr 0 ;
}

Das erste Programm erklärte das Problem, dem wir ohne einen virtuellen Destruktor gegenüberstehen. Dieser Code löst dieses Problem nun mit einem virtuellen Destruktor. Kopieren Sie zuerst den ersten Code und fügen Sie einfach ein Schlüsselwort an zwei Stellen in diesem Programm hinzu. Dieses Wort ist „virtuell“. Fügen Sie dieses Wort mit dem Destruktor der übergeordneten Klasse „Parent_Class0“ ein. Erwähnen Sie dies in ähnlicher Weise mit dem Destruktor der untergeordneten Klasse, der „Child_1“ ist, der von der übergeordneten Klasse abgeleitet ist. Dieses „virtuelle“ Schlüsselwort nimmt eine kleine Änderung vor und führt zuerst den Destruktor der untergeordneten Klasse „Child_1“ aus. Dann führt es den Destruktor der übergeordneten Klasse „Parent_Class0“ aus. Der Rest des Programms funktioniert genauso wie ohne einen virtuellen Destruktor. Indem wir dieses kleine Stück Code hinzufügen, können wir unseren Speicher vor Lecks schützen. Jetzt zeigt es vier Meldungen auf der Konsole an. Zuerst der Konstruktor einer Elternklasse, dann der Konstruktor einer Kindklasse, der Destruktor einer Kindklasse und der Destruktor einer Elternklasse. Am Ende löschen wir den Zeiger innerhalb der Methode main().

Ausgabe:

C++-Beispiel für einen reinen virtuellen Destruktor

In diesem Code werden wir über den rein virtuellen Destruktor sprechen, wie er funktioniert und wie er sich von einem virtuellen Destruktor unterscheidet.

Code:

#include

Klasse Parent_0 {
Öffentlichkeit :
virtuelles ~Parent_0 ( ) = 0 ;
} ;
Elternteil_0 :: ~Eltern_0 ( )
{
Standard :: cout << 'Hallo, ich bin Pure Destructor. Du hast mich angerufen!' ;
}
Klasse Kind_0 : öffentlich Parent_0 {
Öffentlichkeit :
~Kind_0 ( ) { Standard :: cout << 'Abgeleiteter Destruktor ist hier \n ' ; }
} ;

int hauptsächlich ( )
{
Elternteil_0 * ptr_0 = neues Kind_0 ( ) ;
lösche ptr_0 ;
Rückkehr 0 ;
}

Im ersten Schritt des Codes wird die übergeordnete Klasse „Parent_0“ erstellt. Erstellen Sie darin den virtuellen übergeordneten Destruktor und weisen Sie ihm 0 zu. Dadurch wird der virtuelle Destruktor auf einen reinen virtuellen Destruktor gesetzt, was bedeutet, dass die übergeordnete Klasse jetzt abstrakt ist und wir die Instanzen dieser Klasse nicht erstellen können. Definieren Sie außerhalb der übergeordneten Klasse „Parent_0“ die Destruktoren und std::cout. Der erforderliche Text wird mithilfe von std::cout angezeigt. Leiten Sie dann eine „Child_0“-Klasse von der übergeordneten Klasse ab und definieren Sie ihren Destruktor. Geben Sie im Destruktor eine Nachricht aus. Erstellen Sie in der Funktion main() den Zeiger der übergeordneten Klasse und weisen Sie ihm die untergeordnete Klasse zu.

Der Compiler geht zur übergeordneten Klasse „Parent_0“. Wenn der Zeiger erstellt wird, wird sein Konstruktor automatisch aufgerufen. Dann geht der Compiler in die untergeordnete Klasse, um ihren Konstruktor aufzurufen. Nach erfolgreicher Ausführung des Konstruktors führt dieser den Destruktor einer Kindklasse „Child_0“ aus. Dann führt es den Destruktor einer übergeordneten Klasse aus. Auf diese Weise können wir einen reinen virtuellen Destruktor erstellen. Es wird nicht empfohlen, es zu verwenden, da durch die Verwendung dieser Methode die Elternklasse abstrakt wird, was sie nutzlos macht. Die am häufigsten verwendete Methode ist der virtuelle Destruktor, und dies ist eine bewährte Vorgehensweise.

Ausgabe:

Fazit

Wir haben den virtuellen Destruktor kennengelernt, beginnend mit dem Konzept von OOP bis hin zu den Konstruktoren und Destruktoren. Nachdem wir all dies erklärt hatten, diskutierten wir ausführlich über den virtuellen Destruktor mit Codierungsbeispielen und reinem virtuellen Destruktor. Bevor wir den virtuellen Destruktor erklären, müssen wir etwas über Konstruktoren, Destruktoren und Vererbung wissen. Bei der Vererbung erben wir die Klassen von einer übergeordneten Klasse. Die untergeordneten Klassen können mehr als eine sein, aber die übergeordnete Klasse ist nur eine. Virtuelle Destruktoren und rein virtuelle Destruktoren werden bei der Vererbung angewendet, um Speicherlecks zu vermeiden. Vom einfachen Beispiel bis zum erweiterten Beispiel haben wir alles behandelt, was Sie wissen sollten, um mit der Verwendung und virtuellen Zerstörung des Speichers der abgeleiteten Klasse zu beginnen.