Kada naudoti virtualius destruktorius?

Gerai suprantu didžiąją dalį OO teorijos, bet vienas dalykas, kuris mane labai glumina, yra virtualūs destruktoriai.

Maniau, kad destruktorius visada yra iškviečiamas nepriklausomai nuo to, koks jis yra, ir kiekvienam grandinėje esančiam objektui.

Kada juos reikia padaryti virtualius ir kodėl?

Sprendimas

Virtualūs destruktoriai yra naudingi, kai išvestinės klasės egzempliorius gali būti ištrintas per rodyklę į bazinę klasę:

class Base 
{
    // some virtual methods
};

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

Čia pastebėsite, kad nedeklaravau, jog Base destruktorius yra virtualus. Dabar pažvelkime į šią ištrauką:

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

Kadangi Base's destruktorius nėra virtualus, o b yra Base*, nurodantis į Derived objektą, delete b turi neapibrėžtą elgesį:

[Įrašant delete b], jei statinis tipas šalinamas objektas skiriasi nuo jo dinaminio tipo, statinis tipas tipas turi būti šalinamo objekto dinaminio tipo bazinė klasė. ištrinti, o statinis tipas turi turėti virtualų destruktorių arba elgesys yra neapibrėžtas.

Daugumoje realizacijų destruktoriaus iškvietimas bus išspręstas kaip bet koks nevirtualus kodas, t. y. bus iškviestas bazinės klasės destruktorius, bet ne išvestinės klasės destruktorius, todėl atsiras išteklių nutekėjimas.

Apibendrinant galima pasakyti, kad bazinių klasių destruktoriai visada turi būti virtualūs, kai jais norima manipuliuoti polimorfiškai.

Jei norite užkirsti kelią egzemplioriaus ištrynimui per bazinės klasės rodyklę, galite bazinės klasės destruktorių padaryti apsaugotą ir nevirtualų; tokiu būdu kompiliatorius neleis jums iškviesti delete bazinės klasės rodyklei.

Daugiau apie virtualumą ir virtualųjį bazinės klasės destruktorių galite sužinoti šiame Herb Sutter straipsnyje.

Komentarai (10)

Polimorfinėse bazinėse klasėse destruktorius deklaruokite kaip virtualius. Tai 7 punktas Scott Meyers' Effective C++. Toliau Meyersas apibendrina, kad jei klasė turi bet kokią virtualią funkciją, ji turėtų turėti virtualų destruktorių, o klasės, neskirtos būti bazinėmis klasėmis arba neskirtos naudoti polimorfiškai, neturėtų nedeklaruoti virtualių destruktorių.

Komentarai (7)

Jei jūsų klasė yra polimorfinė, destruktorių paverskite virtualiu.

Komentarai (0)