C++: Why virtual? (Part-2)

An interface is a contract between a caller and a callee. An interface doesn’t provide any implementation. It provides a blue-print. C++ uses virtual keyword to create an interface or an abstract class.

Lets take an example:

class IHello
{
public:
	virtual void SayHello() = 0;
};

IHello is an interface with SayHello function prototype. We can’t create an instance for IHello class. Because this is an abstract class (a class with 0 or more pure virtual functions); it’s not possible to create an instance for these classes. The following code throws errors.

int main()
{
	IHello hello;

	return 0;
}

The above code will generate the below error:

error C2259: 'IHello' : cannot instantiate abstract class due to following members:
        'void IHello::SayHello(void)' : is abstract

The only way to create an instance for this class is implement the SayHello function in its derived class and instantiate the derived class. The code looks like below: This code will work without any errors.

class CHello : public IHello
{
public:
	void SayHello()
	{
		cout << "Hello!" << endl;
	}
};

int main()
{
	CHello hello;
	hello.SayHello();

	return 0;
}

Another place where C++ uses virtual keyword is at class’s destructor. Class’s constructor is to construct a class; all the class’s initialization code goes here. Class’s destructor is to release any memory allocated to the class’s members.

Class’s constructor is called at the time of instantiating the class. Means at the time of creating an object of a class. Class’s destructor is called when the object is out of scope or object is going to destruct.

In case of inheritance, if we instantiate derived class; first base class’s constructor will call before calling derived class’s constructor. But destructors will call in reverse order; first derived class’s destructor will call before calling base class’s destructor.

Look at the below example:

class Shape
{
public:
	Shape()
	{
		cout << "Shape's constructor called" << endl;
	}
	~Shape()
	{
		cout << "Shape's destructor called" << endl;
	}
};

class Circle : public Shape
{
public:
	Circle()
	{
		cout << "Circle's constructor called" << endl;
	}
	~Circle()
	{
		cout << "Circle's destructor called" << endl;
	}
};

int main()
{
	Circle circle;

	return 0;
}

Once you run this code, it will display the below result.

Shape's constructor called
Circle's constructor called
Circle's destructor called
Shape's destructor called

Observe the sequence of calling constructors and desctructors. This is perfectly fine if it executes in the same order what we have seen. But in case of destructors, there is a chance of altering the calling sequence of destructors.

Look at the below code:

int main()
{
	Shape *pShape = new Circle();
	if ( pShape != NULL )
	{
		delete pShape;
		pShape = NULL;
	}
}

This code just creating an object of “Circle” and if it successfully created, destroying the object. The tricky part here is, “Circle” object is assigned to “Shape” type variable. This is acceptable; because Shape class is the base class for Circle.

But when we run the program; it will show the below result:

Shape's constructor called
Circle's constructor called
Shape's destructor called

Observe that, Circle‘s destructor never called in this situation. Because, Circle‘s instance is assigned to Shape type variable. Compiler assumes that, the object is of type Shape even though actual object type is Circle. In this case compiler will depend on early binding (where types resolved at compile time). But in our code, the types resolved at run-time (late-binding). So, compiler is unable to recognize the actual type. Hence it never called Circle‘s destructor.

To resolve this problem, add virtual keyword to Shape‘s destructor. Lets add the virtual keyword to Shape class and re-run the application.

class Shape
{
public:
	Shape()
	{
		cout << "Shape's constructor called" << endl;
	}
	virtual ~Shape()
	{
		cout << "Shape's destructor called" << endl;
	}
};

After running this, the order of calling constructors and destructors are proper and the results are as we expected.

We will discuss another place where virtual keyword is used in C++, in our next article.

**

Leave a Reply