Search code examples
c++virtualdestructor

What is the difference between virtual function and virtual destructor function?


class Base {
    public:
    virtual ~Base () { cout << "Base Dtor" << endl; }
    virtual void doSomething () { cout << "Base do something" << endl; }
};

class Derive : public Base {
    public:
    ~Derive () { cout << "Derive Dtor" << endl; }
    void doSomething () { cout << "Derive do something" << endl; }
};

when I try to write some code like:

Base* ptr = new Derive;
ptr->doSomething ();
delete ptr;

the function doSomething() is called correctly. Why the derived destructor is called and then base destructor is called? But doSomething() just only call the derived class's version. Destructor and doSomething() are also function but why do they behave differently?


Solution

  • Object destructors are special. Yes, they are functions, but they actually represent something particular. Namely, destroying an object.

    In your example Derive is an object. But through inheritance, Derive has a base class subobject called Base. That is, for every Derive, there is also a Base living within that Derive object.

    When you invoke a constructor to create a Derive, the appropriate constructor will be invoked for the Base subobject as well (depending on how you defined your Derive constructor). As such, if you destroy a Derive, the Base living inside of it must also be destroyed.

    The virtual call to the destructor doesn't actually change this. What it being virtual does is allow the system to start the chain of destructors correctly. If you had not declared the Base destructor to be virtual, then invoking delete on a base class pointer would only invoke ~Base. It wouldn't be able to jump up the inheritance graph to call ~Derive; the delete expression is given a Base pointer to delete, so that's what it does.

    This is the same mechanism as any virtual call. If you didn't make a regular member function virtual, and you call it on a Base class pointer, then you get the Base version of it, even if there is a Derive version with the same name. You need virtual to make the compiler jump up the inheritance graph and find the right function to call.

    But once the compiler knows the right object type to start the chain of destructors, that chain of object destruction will still happen. Derive contains a Base, so for a Derive to be destroyed, its Base must also be destroyed.