Search

12.3 — Virtual destructors, virtual assignment, and overriding virtualization

Virtual destructors

Although C++ provides a default destructor for your classes if you do not provide one yourself, it is sometimes the case that you will want to provide your own destructor (particularly if the class needs to deallocate memory). You should always make your destructors virtual if you’re dealing with inheritance. Consider the following example:

Because base is a Base pointer, when base is deleted, the program looks to see if the Base destructor is virtual. It’s not, so it assumes it only needs to call the Base destructor. We can see this in the fact that the above example prints:

Calling ~Base()

However, we really want the delete function to call Derived’s destructor (which will call Base’s destructor in turn), otherwise m_array will not be deleted. We do this by making Base’s destructor virtual:

Now this program produces the following result:

Calling ~Derived()
Calling ~Base()

Rule: Whenever you are dealing with inheritance, you should make any explicit destructors virtual.

Virtual assignment

It is possible to make the assignment operator virtual. However, unlike the destructor case where virtualization is always a good idea, virtualizing the assignment operator really opens up a bag full of worms and gets into some advanced topics outside of the scope of this tutorial. Consequently, we are going to recommend you leave your assignments non-virtual for now, in the interest of simplicity.

Ignoring virtualization

Very rarely you may want to ignore the virtualization of a function. For example, consider the following code:

There may be cases where you want a Base pointer to a Derived object to call Base::getName() instead of Derived::getName(). To do so, simply use the scope resolution operator:

You probably won’t use this very often, but it’s good to know it’s at least possible.

12.4 -- Early binding and late binding
Index
12.2a -- The override and final specifiers, and covariant return types

37 comments to 12.3 — Virtual destructors, virtual assignment, and overriding virtualization

  • sarvesh

    Alex
    Which destructor should be virtual here ? It is base class destructor.
    Comment added in code section is not correct
    virtual ~Derived() // note: virtual
    ~Derived() // note: not virtual

    You have to move these both comments to base class destructor.

  • Tim Hothersall

    It did not take a great deal of time for my to understand the basic principle of polymorphism, but I had a hell of a job justifying it and understanding its full potential.  Inheritance I use all the time, but it took about 8 months for me to use polymorphism in a meaningful way.

    Although I am far from experienced, I have noted that there seems to be a tendency for programmers to use functionality because it is there rather than because it is beneficial to the program. Maybe I am wrong to think like this; I don’t know, but I try to only use things that are helpful. (using the right tool for the right job rather than using a sledgehammer to crack a nut).

    One thing that I didn’t realise and why it took me so long to find polymorphism useful is that calling a virtual function within a method in a base class will jump to the derived version of the function if there is one.  Looking back over this tutorial now, I can see that this is explained, but I just didn’t see it for some reason.

    • Alex

      Yup. Virtual functions are fantastic, but only for solving particular types of problems. For other kinds of problems, other tools are more appropriate. As you say, use the right tool for the job at hand.

  • First, Thanks for replying quickly on comments 🙂

    I don’t understand the part with deleting that calls the base portion destructor of a derived class, when the destructor is not virtual… What happens with the derived part of the object, it gets deleted too with some default destructor or remains as garbage in memory?? If it remains, we could point to it and use non-inherited members and functionality with undefined results, so I guess that must be false…

    • Alex

      If you have an object of a derived class, and your base class destructor isn’t virtual, and you delete a pointer to the base portion of that class, only the base portion of the class gets deleted. The derived portion stays in memory with no way to get to it, so that memory is leaked/lost until your program is terminated and the operating system cleans up.

  • Mario

    Above you said: "Rule: Whenever you are dealing with inheritance, you should make any explicit destructors virtual."

    Is there any reason to not make any destructors virtual ever? Or can I safely make every destructor I write virtual?

    Regards 🙂

    • Alex

      > Is there any reason to not make any destructors virtual ever? Or can I safely make every destructor I write virtual?

      In general, you should only make your destructor virtual if you have some other virtual function in the class. As soon as you add any virtual functions, every object of your class now needs a symbol table, which means you’ve increased the size of your class objects by a pointer, and made them slightly less efficient (it takes longer to call a virtual function than a non-virtual one). Why pay this performance penalty unless you’re actually using virtual functions for their intended purpose?

  • Sam

    line 22 in the second code block: wrong commentary

  • Don jose

    Hi Alex,

    I am not getting why my destructors getting called two times
    the code is below

    Output is:
    Derived
    Base
    Derived
    Base
    (Using code block compiler)

    Thnaks in advance.. Great tutorial ever

    • Alex

      When you delete ptr, contents that ptr are pointing to are being destroyed, which calls the destructor.
      Then when D1 goes out of scope, it gets destroyed, which also calls the destructor.

      In this particular case, this will cause problems because ptr points to D1, so the same thing is getting deleted twice. You should generally only delete a pointer if you’ve allocated memory for it using new -- which you haven’t done here.

  • Darren

    Just when I think I’ve got a reasonable handle on the language along comes a curve ball about virtual assignment operators - what on earth? I’m going to guess based on the information I have on the virtual keyword when used with member functions. A virtual assignment operator probably calls the most-derived assignment operator in an inheritance chain meaning that you only change the most derived part of an object rather than changing an object in its entirety? Sounds sensible if the object is large. Am I anywhere near?

    • Alex

      Typically, a derived assignment operator will call the base-assignment operator to copy the base portion of the class before it copies the derived portion itself (because, after all, if you’re copying a derived object, you want the whole thing, not just the derived portion). This is analogous to how a derived class constructor will call a base class constructor to initialize the base portion of the object before initializing the derived portion.

      Note that typically the parameter for an assignment operator is a reference to an object of the class itself: this means a base class assignment operator will take a base object, and a derived class assignment operator will take a derived object. This gives these functions different signatures, and the compiler will treat them as distinct. So virtualization doesn’t actually help you here.

      Virtualized assignment operators could really be an entire lesson in and of itself. It’s complicated, and has a lot of edge cases to consider.

      • Darren

        I think with a lot of the advanced features of C++ its good to know they exist and have a gist of what they do but unless you’re actually going to use them a full understanding probably isn’t necessary. And when you say "has a lot of edge cases" I hear "lots of potential for causing debugging misery".

  • Ramkrushna Joshi

    Hi alex,one question…

    int main()
    {
        Derived *pDerived = new Derived(5);
        Base *pBase = pDerived;
        delete pBase;

        return 0;
    }
    in this you have deleted pBase,but if we delete pDerived then without virualization of Base destructor,both destructor will be called.
    So my question is cann’t we delete  pDerived…??yes then why need to delete pBase…??

    • Alex

      Yes, of course you can delete pDerived. But there are legitimate cases where you will only have a pointer to the base class. We explore some of those cases in future lessons. This is just setting up the foundation for further understanding.

  • Thanks for this helpful site, Alex, a colon is missing after public at the last example.

  • jonas

    int main()
    {
        Derived *pDerived = new Derived(5);
        Base *pBase = pDerived;
        delete pBase;

        return 0;
    }
    Does pBase point to the same location as pDerived now here? And does deleting pBase dealocate the pDerived itself(since ~Derived() just dealocate m_pnArray)?

    • Alex

      Yes, pBase and pDerived will hold the same address (of the instanted Derived object).
      Deleteing pBase will deallocate the derived object properly if the Base destructor is properly virtual. If the Base destructor is not virtual, then only the Base portion of the class will be deleted (causing a memory leak).

  • Night Owl

    I am a bit confused why you had to dynamically allocate pDerived, if the Derived constructor dynamically allocates an array. Is there a relationship between them at all?

    Since you deleted pBase, consequently deleting the address that both pBase and pDerived was pointing to, are both of them now pointing to nothing? Would setting those pointers to null be necessary in this case?

    • Alex

      There’s no relationship between dynamically allocating pDerived and the fact that Derived objects dynamically allocate an array themselves.

      Deleting a pointer doesn’t cause the value that the pointer holds to change. The pointer is left holding the address of memory that has been deallocated (making it a hanging pointer). Using such a pointer is dangerous.

      Normally you’d want to set the value of a pointer that has been deleted to null, but in this case since the program terminates anyways immediately afterward, it’s not necessary.

  • Devashish

    Stack overflow cleared some confusions. Pointers aren’t instances. They only hold address of an instance of same type. If pointer is assigned a dynamically allocated instance, when its block ends, pointer gets destroyed and that causes a memory leak. And because pointers aren’t instances, destructor isn’t called when it goes out of scope.

  • Devashish

    Some confusions:

    “When a variable goes out of scope, or a dynamically allocated variable is explicitly deleted using the delete keyword, the class destructor is called (if it exists) to help clean up the class before it is removed from memory” from 8.6 Destructors.

    It might seem stupid, but my question is that why Destructor of Derived isn’t called here? The class Derived also have a destructor. ~Base is called when we delete pBase. But, according to previous lessons, there is another case where destructors are called that is, when a variable of that class goes out of scope. At the end of main, pDerived is going out of scope, but ~Derived is not called. Why…??? If I remove this line: delete pBase; from the code above, nothing is called when variables go out of scope.I found an interesting fact, that destructors aren’t called when variables are pointers that points to an object. Am I right???

    • Alex

      When a pointer goes out of scope, the object it is pointing to is not destroyed. Only the pointer (holding the address of the object) is destroyed.

      To destroy the object itself, you have to use delete.

      In the example above, when you delete pBase, the Derived constructor will be called if the destructors have been properly virtualized.

  • pranesh

    please have a look at the following code :

    Now this program produces the following result:

    Calling ~Derived()
    Calling ~Base()

    i am unable to understand why ‘calling ~Base()’ is been printed here?
    when we reached delete pbase; in int main() it goes to Base class first and finds that its destructor is virtual so it goes to Derive class and finds another destructor and executes it but why does it prints ~Base() in any case?

    • jason

      i’m also stuck in the same question!may be when derivative destructor is called,then the cursor returns to base for executing line 31 but it should again call derived destructor as again it will come across the virtual base destructor! someone help please!

    • Gigwig

      That is the thing with Inheritance, constructors are called, by default, from the base class to the derived class and the destructors run from the derived class to the base class.

      • Alex

        Exactly this. Constructors execute in order from the most-base to most-derived class. Destructors execute in order from most-derived to most-base class.

        If the Base destructor was not virtual, then as far as base knows, Base is the most derived class, so only the ~Base constructor would execute. However, since the Base destructor is virtualized, base knows that there’s a Derived destructor. Consequently, ~Derived executes first, and then ~Base executes second.

  • Sakthi

    Hello Alex,
    I assume you must have overloaded the new, delete and paranthesis operators. Could you show the code for this ?
    If not then HOW do these operators work with classes ‘Derived’ and ‘Base’ ?
    new int[5] makes sense. but new Derived(5) does not .
    This is driving me nuts. Please help.

  • Lion

    Really rocking and mind blowing explanation.:D

    Thanks a lot Alex.

  • Lee

    HI,

    I want to call a derived class function, that isn’t defined in the base class, using base class pointers. but this always raises the error:

    error C2039: ‘derivedFunctionName’ : is not a member of ‘BaseClass’

    Do you know how i could get around this?

    Thanks,

    Lee.

    • Add a virtual function of the same name into the base class. You can define the base-class function with an empty body, or even better, make it a pure virtual (abstract) function.

  • Kinten

    I understood it, but I get the feeling that I will forget it really soon, maybe some practice is needed :[
    Well explained, thx

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter