Virtual Destructors

Interview questions often ask about virtual destructors and why they are needed. It’s one of those funny things about C++ that unless you have specifically been shown, you just might not realise you need to know.

So why do you need a virtual destructor?

Essentially, you need a virtual destructor to make sure that ALL the relevant destructors are called when you delete an object via a base class pointer.

Huh?

Well, that actually sounds far more complicated than it is.

Let’s use an example to make it easier. Imagine you have a base class called Container and a sub class called CardboardBox. You create a CardboardBox, and then use the base class pointer to access it (why? see below). When you’re all done, it’s time to delete your object.

Now, the base class doesn’t do much in the way of clearing up, but the subclass (the cardboard box), can be recycled.

So, when your base class destructor is virtual, deleting the base class pointer will call the sub class destructor without you having to do anything extra – and the box will be recycled as if by magic.

If, however, your base class destructor is not virtual, only the base class destructor will get called and the recycling will not happen. Very bad for the environment.

Ouch.

Let’s see this in action with a code example:

#include <iostream> 
using namespace std;

class Container
{
public:
	Container() {};
	virtual ~Container()
	{
		cout << "Base class destructor called - not much to do." << endl;
	};
};

class CardboardBox: public Container {
public:
	CardboardBox() {};
	~CardboardBox()
	{
		cout << "Sub class destructor called - let's recycle the cardboard!" << endl;
	};
};

int main()
{
	CardboardBox* box = new CardboardBox;

	Container* p = box;

	delete p;

	return 0;
}

When the destructor is virtual (as it should be), the output of this program is as follows:

virtual1

You can see that both the sub class and the base class destructors have been called, and you have been a green and conscientious consumer.

However, if you remove the ‘virtual’ keyword from the base class destructor, the output changes to this:

virtual2

Oh dear. No one recycled their cardboard today.

So you see, making your base class destructors virtual will help keep everything nice and tidy. Which is of course, just how we like it 🙂

Why are you using a base class pointer to access the cardboard box?

This is the key to polymorphism in C++. You can use a base class to interface with objects without knowing what they are. So in this example you can talk to objects via the base class (Container), and you don’t need to specifically know whether they are cardboard boxes, metal boxes, or wicker baskets!

I’ve a fuller explanation of polymorphism here.

Eclipse-CDT: Base class ” not in include paths for current project

eclipseDon’t you just hate weird things like this? You have a nice little project in Eclipse, it’s all is working fine, auto-complete, build, everything.

BUT:

When you try to add a new class using the File -> New -> Class menu, you get this error:

Base class 'myclassname' not in include paths for current project.

Doh!

This one is easy to fix.

Read more

Polymorphism and Overloading in C++

A reader sent me an interesting question the other day. They asked if polymorphism and overloading were essentially the same thing.

My initial reaction was Huh?

What are people being taught if they think that these two concepts are the same thing?

But a quick google search revealed that yes, many, many people are struggling to differentiate between these two terms – and the internet is full of conflicting and unhelpful information.

Read more

Polymorphism Example in C++

If you’ve read my 5 minute guide What Is Polymorphism? and want to see it in action, here’s some C++ code that illustrates the example I mentioned in that post.

I’ve kept the code to header files only for brevity, but as you well know, in the real world, objects would be split out into .h and .cpp files. The program consists of the main.cpp file, a base class called Mammal, and three derived classes called Dog, Cat and Mouse.

1. main.cpp

This is where it all comes together and you see polymorphism in action. I’ve declared an array of pointers to the Mammal base class, and for each one have called the SendLoudNoise() method. The output of the program should look like this:

Woof woof!
--- Twitch my tail ---
--- Sniff the air ---

Which means that although I am calling the method on the base class, it is the derived class that is responding, as it overrides the SendLoudNoise() method in each case.

#include <iostream>
#include "Mammal.h"
#include "Dog.h"
#include "Cat.h"
#include "Mouse.h"

const int cNumAnimals = 3;

int main()
{
	Mammal* pAnimal[cNumAnimals] = { new Dog, new Cat, new Mouse };

	for (int i = 0 ; i < cNumAnimals ; ++i)
	{
		std::cout << pAnimal[i]->SendLoudNoise() << std::endl;
		delete pAnimal[i];
	}

	return 0;
}

2. Mammal.h

The Mammal class, our base class, defines the virtual method SendLoudNoise(), but we never see the text that this method outputs. This proves that our polymorphism example is working correctly.

Note that methods you want to override must be declared as virtual. If you remove this one keyword, the output of the program would be 3 lines of “I am a generic mammal”!

#ifndef MAMMAL_H_
#define MAMMAL_H_

#include <string>

class Mammal {
public:
	Mammal() {};
	virtual ~Mammal() {};

	virtual std::string SendLoudNoise()
	{
		std::string str("I am a generic mammal");
		return str;
	}
};

#endif /* MAMMAL_H_ */

3. Dog.h

The next three files are very similar. Each one inherits from the Mammal class and then overrides the SendLoudNoise() method. Aside from that, they are almost identical.

You don’t have to override a method in a derived class. If you wanted default behaviour, you could specify that in your base class and not mention it in your derived class. Then when that method is called, the object would default to using the base class version.

#ifndef DOG_H_
#define DOG_H_

#include "Mammal.h"

class Dog : public Mammal {
public:
	Dog() {};
	virtual ~Dog() {};

	std::string SendLoudNoise()
	{
		std::string str("Woof woof!");
		return str;
	}
};

4. Cat.h

#ifndef CAT_H_
#define CAT_H_

#include "Mammal.h"

class Cat : public Mammal {
public:
	Cat() {};
	virtual ~Cat() {};

	std::string SendLoudNoise()
	{
		std::string str("--- Twitch my tail ---");
		return str;
	}
};

#endif /* CAT_H_ */

5. Mouse.h

#ifndef MOUSE_H_
#define MOUSE_H_

#include "Mammal.h"

class Mouse : public Mammal {
public:
	Mouse() {};
	virtual ~Mouse() {};

	std::string SendLoudNoise()
	{
		std::string str("--- Sniff the air ---");
		return str;
	}
};

#endif /* MOUSE_H_ */

And that’s all there is to it – a very basic example of using polymorphism to enable interaction with different objects via a base class pointer.