Virtual destructor in polymorphic classes

前端 未结 2 1797
一整个雨季
一整个雨季 2021-01-13 19:17

I understand that whenever you have a polymorphic base class, the base class should define a virtual destructor. So that when a base-class pointer to a derived-class object

相关标签:
2条回答
  • 2021-01-13 19:49

    If at the point where you delete the object the static type of the variable is the bas type, than the destructor of the base type will be called, but the destructor of the sub class won't be called (as it is not virtual).

    As a result the resources allocated by the base class will be freed, but the resources allocated by the sub class won't.

    Thus the object won't be destructed correctly.

    You are correct about that table: it is called a virtual method table or "vtable". But the result of the destructor being non-virtual is not that the destructors are not called in the correct order, but that the destructor(s) of the sub class(es) are not called at all!

    0 讨论(0)
  • 2021-01-13 19:51

    Consider

    struct Base {
        void f() { printf("Base::f"); }
    };
    struct Derived : Base {
        void f() { printf("Derived::f"); }
    };
    Base* p = new Derived;
    p->f();
    

    This prints Base::f, because Base::f is not virtual. Now do the same with destructors:

    struct Base {
        ~Base() { printf("Base::~Base"); }
    };
    struct Derived : Base {
        ~Derived() { printf("Derived::~Derived"); }
    };
    Base* p = new Derived;
    p->~Base();
    

    This prints Base::~Base. Now if we make the destructor virtual, then, as with any other virtual function, the final overrider in the dynamic type of the object is called. A destructor overrides a virtual destructor in a base class (even though its "name" is different):

    struct Base {
        virtual ~Base() { printf("Base::~Base"); }
    };
    struct Derived : Base {
        ~Derived() override { printf("Derived::~Derived"); }
    };
    Base* p = new Derived;
    p->~Base();
    

    The call p->~Base() actually invokes Derived::~Derived(). Since this is a destructor, after its body finishes executing, it automatically invokes destructors of bases and members. So the output is

    Derived::~Derived
    Base::~Base
    

    Now, a delete-expression is in general equivalent to a destructor call followed by a call to a memory deallocation function. In this particular case, the expression

    delete p;
    

    is equivalent to

    p->~Base();
    ::operator delete(p);
    

    So if the destructor is virtual, this does the right thing: it calls Derived::~Derived first, which then automatically calls Base::~Base when it's done. If the destructor isn't virtual, the likely result is that only Base::~Base is invoked.

    0 讨论(0)
提交回复
热议问题