Navigation



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:

class Base
{
public:
    ~Base()
    {
        cout << "Calling ~Base()" << endl;
    }
};

class Derived: public Base
{
private:
    int* m_pnArray;

public:
    Derived(int nLength)
    {
        m_pnArray = new int[nLength];
    }

    ~Derived() // note: not virtual
    {
        cout << "Calling ~Derived()" << endl;
        delete[] m_pnArray;
    }
};

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

    return 0;
}

Because pBase is a Base pointer, when pBase 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). We do this by making Base’s destructor virtual:

class Base
{
public:
    virtual ~Base()
    {
        cout << "Calling ~Base()" << endl;
    }
};

class Derived: public Base
{
private:
    int* m_pnArray;

public:
    Derived(int nLength)
    {
        m_pnArray = new int[nLength];
    }

    virtual ~Derived()
    {
        cout << "Calling ~Derived()" << endl;
        delete[] m_pnArray;
    }
};

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

    return 0;
}

Now this program produces the following result:

Calling ~Derived()
Calling ~Base()

Again, whenever you are dealing with inheritance, you should make your 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.

Overriding virtualization

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

class Base
{
public:
    virtual const char* GetName() { return "Base"; }
};

class Derived: public Base
{
public
    virtual const char* GetName() { return "Derived"; }
};

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:

int main()
{
    Derived cDerived;
    Base &rBase = cDerived;
    // Calls Base::GetName() instead of the virtualized Derived::GetName()
    cout << rBase.Base::GetName() << endl;
}

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

The downside of virtual functions

Since most of the time you’ll want your functions to be virtual, why not just make all functions virtual? The answer is because it’s inefficient — resolving a virtual function call takes longer than a resolving a regular one. Furthermore, the compiler also has to allocate an extra pointer for each class object that has one or more virtual functions. We’ll talk about this more in the next couple of lessons.

12.4 — Early binding and late binding
Index
12.2 — Virtual functions

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

  • [...] Posts « 12.1 — Pointers and references to the base class of derived objects | Home | 12.3 — Virtual destructors, virtual assignment, and overriding virtualization » Wednesday, January 30th, 2008 at 3:46 [...]

  • sandhya

    Hi Alex,

    In the example for virtual destructor
    class Derived: public Base
    {
    private:
    int* m_pnArray;

    public:
    Derived(int nLength)
    {
    m_pnArray = new int[nLength];
    }

    virtual ~Derived()
    {
    cout << “Calling ~Derived()” << endl;
    delete m_pnArray;
    }
    };

    In the constructor, you have dynamically allocated an integer array using new operator. But in destructor, you have used only “delete m_pnArray;” where u should have used “delete[] m_pnArray;”. Correct me if i am wrong.

    • You are correct. This is one of the things I constantly screw up in C++.

      • Ben

        What a stupid mistake, i would never do this. Every child knows, that you have to delete () m_pnArray…
        Damn it, i really did it with this sort of brackets and it was quite confusing, because i didn’t see the mistake at first glance.

        • Sorry I know that this is telling me something. I get most of it.

          But at the risk of sounding like a total tool, ok here goes!:

          Why do you need to use a pointer from the base class? This seems to be the main reason we need these virtual functions.

          Why not just use a pointer created from the Derived class?

          Please feel free to call me an idiot, but I’m sure with a good reason for this I’ll get it. it just escapes me a bit at the moment. Sorry.

          EDIT:
          Sorry this was supposed to be a stand alone question not a reply to Ben.

  • [...] 2007 Prev/Next Posts « 12.3 — Virtual destructors, virtual assignment, and overriding virtualization | Home | 12.5 — The virtual table » Thursday, February 7th, 2008 at 3:46 [...]

  • Kinten

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

  • 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.

  • Can you override a virtual function when you have used a pointer instead of a reference?

    EDIT:
    Woops! Yes you can
    Derived cDerived;
    Base *rBase = &cDerived;
    cout << "rBase is a " << rBase->Base::GetName() << endl;

  • Mario_G

    Hi Alex,

    I like the “Rule: ” part, it’s a good reminder
    Maybe some “Tips: ” part could be great, like
    “Tips: Whenever you are dealing with inheritance, you should make your destructors virtual.”

    I’m going thru you website and taking notes of the “Rules: ” and sometimes “Tips: ” might be appreciated and easier to find important things to remember or consider.

  • Lion

    Really rocking and mind blowing explanation.:D

    Thanks a lot Alex.

  • josabraham

    int main()

    29 {

    30 Derived objDerived ;

    31 Base *pBase = &objDerived ;

    32 delete pBase; //Will call derived and base destructors

    33

    34 return 0;

    35 }

  • prags

    HI,
    i wanted to clarify my doubt regarding virtual functions.
    i.e;when v r using the concept of virtual functions,is it necessary dat v shud use d same name for all the functions vich r declared as virtual??especially while showing virtual functions are hierarchical..

  • 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.

  • [...] destructor was made virtual so that if the class is inherited, then calling a destructor on an object of this class will also call the destructors of inherited class. Read more about it here. [...]

You must be logged in to post a comment.