Miután beszéltünk az OOP-ról, a konstruktorokról és a destruktorokról, most beszéljünk a virtuális destruktorokról. A virtuális destruktorok, ahogy a név is meghatározza, megsemmisíti az objektumot. Van egy alaposztályunk és egy származtatott osztályunk, amely az alaposztályból származik. Mindkét osztálynak megvannak a konstruktorai és destruktorai. A virtuális destruktor felszabadítja a visszaemlékezéseket, amelyek a származtatott osztály objektumon keresztül kerülnek kiosztásra, miközben törli a származtatott osztály objektumait a „virtual” kulcsszóval ellátott alaposztálymutató használatával.
Miért használjuk a Virtual Destructort?
Amikor az osztálytagfüggvények végrehajtása befejeződött, vagy a main() metódus végrehajtása hamarosan véget ér, a destruktor automatikusan meghívásra kerül, hogy felszabadítsa az objektum létrehozása során lefoglalt memóriát. Most miért használunk virtuális destruktort? A származtatott osztályra mutató alaposztály törlésekor itt a mutató (*) kerül felhasználásra. Az alaposztály-destruktor csak ebben a folyamatban kerül meghívásra. A származtatott osztálydestruktort nem hívják meg, ami problémákhoz vezet. Az egyik a memóriaszivárgás problémája. A probléma elkerülése és a kódunk biztonságossá tétele érdekében gyakorlatilag megsemmisítjük az objektumokat, hogy az alaposztály-destruktor törlésével felszabadítsuk az objektumok létrehozása során lefoglalt memóriaterületet.
C++ alappélda Virtual Destructor nélkül
Nézzük meg, hogyan működik a program virtuális destruktor nélkül egy egyszerű programmal, amely törli a mutatót.
Kód:
#includenévtér std használatával ;
osztály Szülő_osztály0
{
nyilvános :
Szülő_osztály0 ( )
{ cout << 'Szülői osztályépítő' << endl ; }
~Parent_Class0 ( )
{ cout << 'Szülői osztályromboló' << endl ; }
} ;
osztály Gyermek_1 : nyilvános Parent_Class0
{
nyilvános :
Gyermek_1 ( )
{ cout << 'Gyermekosztály építő' << endl ; }
~Gyermek_1 ( )
{ cout << 'Gyermekosztály-romboló' << endl ; }
} ;
int fő- ( )
{
Szülő_osztály0 * mutató = új gyermek_1 ( ) ;
mutató törlése ;
Visszatérés 0 ;
}
Ez a kód elmagyarázza, hogyan fut a kód virtuális destruktor nélkül. Először is hozzon létre egy „Parent_Class0” nevű osztályt, amely a szülő osztály lesz. Ezen az osztályon belül hozzon létre egy konstruktort és destruktort. Mint tudjuk, a konstruktor és a destruktor neve ugyanaz, mint az osztály. A destruktort a konstruktorhoz hasonlóan ábrázoljuk, de van egy szimbóluma (~), amely megkülönbözteti a konstruktortól. A konstruktor és a destruktor belsejében nyomtasson egy üzenetet a „cout<<” használatával. Most hozzon létre egy másik osztályt, amely a „Child_1”. Ez az osztály a „Parent_Class0” szülőosztályból származik. A származtatott osztálynak van konstruktora és destruktora, amelyek a kimeneti képernyőn nyomtatandó üzenetet tartalmaznak.
A main() metódusban létrehozzuk a „Parent_Class0” példányát, és hozzárendelünk egy származtatott osztályt. Ebben az esetben emlékezni kell arra, hogy egy mutatót használunk a szülőosztály lekéréséhez. Amikor bemegy a szülő osztályba, végrehajtja a szülő osztály konstruktorát. Ezután a gyermek osztályba lép, és végrehajtja a konstruktorát. Mielőtt végrehajtaná a gyermekosztály destruktorát, végre kell hajtania a szülőosztály destruktorát. A fordító végrehajtja a szülőosztály destruktorát, és leállítja az osztályt anélkül, hogy végrehajtaná a gyermekosztály destruktorát. Ez a baj; nem szabadítja fel a gyermek osztályának emlékét. Egy szülő osztály konstruktorát, egy gyermekosztály konstruktorát és egy szülő osztály destruktorát képviseli. Ez azt mutatja, hogy a gyermekosztály destruktorát nem hajtják végre. A végrehajtás után töröljük a mutatót a main() függvényben.
Kimenet:
C++ példa Virtual Destructorral
Beszéljük meg a virtuális destruktort egy egyszerű kóddal, hogy meg tudjuk különböztetni, hogyan működik virtuális destruktorral és anélkül.
Kód:
#includenévtér std használatával ;
osztály Szülő_osztály0
{
nyilvános :
Szülő_osztály0 ( )
{ cout << 'Szülői osztályépítő' << endl ; }
virtuális ~Parent_Class0 ( )
{ cout << 'Szülői osztályromboló' << endl ; }
} ;
osztály Gyermek_1 : nyilvános Parent_Class0
{
nyilvános :
Gyermek_1 ( )
{ cout << 'Gyermekosztály építő' << endl ; }
virtuális ~Gyermek_1 ( )
{ cout << 'Gyermekosztály-romboló' << endl ; }
} ;
int fő- ( )
{
Szülő_osztály0 * mutató = új gyermek_1 ( ) ;
mutató törlése ;
Visszatérés 0 ;
}
Az első program elmagyarázta a problémát, amellyel virtuális destruktor nélkül szembesülünk. Most ez a kód megoldja ezt a problémát egy virtuális destruktor segítségével. Először másolja ki az első kódot, és adjon hozzá egy kulcsszót két helyen ebben a programban. Ez a szó „virtuális”. Szúrja be ezt a szót a szülőosztály destruktorával, a „Parent_Class0”. Hasonlóképpen említse meg ezt a gyermekosztály destruktorával, amely a szülőosztályból származó „Child_1”. Ez a „virtuális” kulcsszó egy kicsit változtat, és először a „Child_1” gyermekosztály destruktorát hajtja végre. Ezután végrehajtja a szülőosztály destruktorát, a „Parent_Class0”. A program többi része ugyanúgy működik, mint virtuális destruktor nélkül. Ennek a kis kódrészletnek a hozzáadásával megmenthetjük a memóriánkat a szivárgástól. Most négy üzenetet jelenít meg a konzolon. Először a szülőosztály konstruktora, majd a gyermekosztály konstruktora, a gyermekosztály destruktora és a szülőosztály destruktora. A végén töröljük a mutatót a main() metóduson belül.
Kimenet:
C++ Példa a Pure Virtual Destructorra
Ebben a kódban a tiszta virtuális destruktorról fogunk beszélni, hogyan működik, és miben különbözik a virtuális destruktortól.
Kód:
#includeosztály Szülő_0 {
nyilvános :
virtuális ~szülő_0 ( ) = 0 ;
} ;
Szülő_0 :: ~Szülő_0 ( )
{
std :: cout << 'Helló, Pure Destructor vagyok. Te hívtál!' ;
}
osztály Gyermek_0 : nyilvános Szülő_0 {
nyilvános :
~Gyermek_0 ( ) { std :: cout << „Itt van a származtatott romboló \n ' ; }
} ;
int fő- ( )
{
Szülő_0 * ptr_0 = új gyermek_0 ( ) ;
törölje a ptr_0 ;
Visszatérés 0 ;
}
A „Parent_0” szülőosztály a kód első lépésében jön létre. Ezen belül hozza létre a virtuális szülődestruktort, és rendelje hozzá 0-val. Ezzel a virtuális destruktort tiszta virtuális destruktorra állítja be, ami azt jelenti, hogy a szülőosztály most absztrakt, és ennek az osztálynak a példányait nem tudjuk létrehozni. A „Szülő_0” szülőosztályon kívül határozza meg a destruktorokat és az std::cout. A szükséges szöveg az std::cout használatával jelenik meg. Ezután származtasson egy „Child_0” osztályt a szülőosztályból, és határozza meg a destruktorát. Nyomtasson ki egy üzenetet a destruktor belsejében. A main() függvényben hozza létre a szülőosztály mutatóját, és rendelje hozzá a gyermekosztályt.
A fordító a „Szülő_0” szülőosztályba megy. A mutató létrehozásakor a konstruktora automatikusan meghívásra kerül. Ezután a fordító bemegy a gyermekosztályba, hogy meghívja a konstruktorát. A konstruktor sikeres végrehajtása után végrehajtja a „Child_0” gyermekosztály destruktorát. Ezután végrehajtja a szülőosztály destruktorát. Így tiszta virtuális destruktort készíthetünk. Használata nem javasolt, mert ezzel a módszerrel a szülő osztály absztrakttá válik, ami használhatatlanná teszi. A leggyakrabban használt módszer a virtuális destruktor, és ez egy jó gyakorlat.
Kimenet:
Következtetés
Megismertük a virtuális destruktort az OOP koncepciójától kezdve a konstruktorok és destruktorok felé haladva. Mindezek ismertetése után részletesen tárgyaltuk a virtuális destruktort kódolási példákkal és a tiszta virtuális destruktorral. Mielőtt elmagyaráznánk a virtuális destruktort, ismernünk kell a konstruktorokat, destruktorokat és az öröklődést. Az öröklésnél az osztályokat egy szülő osztálytól örököljük. A gyermekosztályok több is lehetnek, de a szülőosztály csak egy. A virtuális destruktorokat és a tisztán virtuális destruktorokat öröklésben alkalmazzák, hogy megmentsék a memóriaszivárgástól. Az alappéldától a haladó példáig mindent lefedtünk, amit tudnia kell, hogy elkezdhesse használni és gyakorlatilag megsemmisítse a származtatott osztály memóriáját.