C++ Polymorphism and Virtual Function

Polymorphism in C++



The word Polymorphism means having many forms

Using polymorphism we can assign different meaning or usage to something in different contexts – specifically, allowing an entity like variable, function, or object to have more than one form. There are different kinds of polymorphism.

In Object Orient Programming, polymorphism represents possibility to have multiple implementations of the same functions. You can see a simple example of polymorphism in “C++ Overloading”. A function with the same name can have different behavior according to the context of its call. The most interesting concepts of polymorphism are related to Inheritance. A pointer of base class can be used as pointer of derived class. Look at the following hierarchy of classes:

class baseClass
{
public:
	baseClass(int val) :someValue(val)
	{

	}
	void info()
	{
		cout << "Info member function of base class" << endl;
	}
protected:
	int someValue;
};

class derivedClass1 : public baseClass
{
public:
	derivedClass1(int val) :baseClass(val)
	{

	}
	void info()
	{
		cout << "Info member function of derived class 1" << endl;
	}
};

class derivedClass2 : public baseClass
{
public:
	derivedClass2(int val) :baseClass(val)
	{

	}
	void info()
	{
		cout << "Info member function of derived class 2" << endl;
	}
};


 

We can use pointer of a base class as a pointer of the derived class:

	
derivedClass1 child1(1);
derivedClass2 child2(2);

//pointers to base class
baseClass* basePtr1;
baseClass* basePtr2;

//make pointers to base class point to objects of derived classes
basePtr1 = &child1;
basePtr2 = &child2;

It seems to be very easy to use pointers of the base class as pointers of the derived class. But the problem appears when

  • We want to call a member function of a derived class that does not exist in the base class or
  • The function which we want to call is overridden in the derived class

Base class and two derived classes have the same function info(). Try to call this function by using pointer to base class as below:

//calling info function
basePtr1->info();
basePtr2->info();

In this case, info() member function of a derived classes will not be called. Instead the info() function of base class will be called. Below is the output of above calls:

Info member function of base class
Info member function of base class

Static Cast

We can use static cast to work with pointer of the base class as pointer of the derived class:

//use static cast and call info from derived class 1
static_cast<derivedClass1*> (basePtr1)->info();

In this case, member function info() from derivedClass1 will be called:

Info member function of derived class 1

Virtual Functions

Virtual functions are functions those are expected to be overridden in the derived class. By using Virtual function we can call functions of a derived class using pointer of the base class.

Declaration of a virtual function is done by using virtual keyword before declaration of a function as shown below:

virtual function-declaration;

Try to declare function info() of the baseClass as virtual function:

virtual void info()
{
	cout << "Info member function of base class" << endl;
}

Now, try to call info function by using pointer of the base class:

derivedClass1 child1(1);
derivedClass2 child2(2);

//pointers to base class
baseClass* basePtr1;
baseClass* basePtr2;

//make pointers to base class point to objects of derived classes
basePtr1 = &child1;
basePtr2 = &child2;

//call info
basePtr1->info();
basePtr2->info();

The appropriate member function of each derived class will be called without any casts then output will be:

Info member function of derived class 1
Info member function of derived class 2

Try to remove info() member function from derivedClass1 and compile this code again then output will be:

Info member function of base class
Info member function of derived class 2

As you can see, compiler first looks for info() member function in the appropriate derived class. If it cannot find member function in the derived class, it will call member function of the base class.

Late binding (Runtime Polymorphism)

Late binding is also known as Dynamic Binding or Runtime Binding.

Sometimes compiler can’t know which function will be called till program is executed (runtime). This is known as late binding.

Binding is the process which is used by the compiler to convert identifiers (such as variable and function names) into machine language addresses.

It is a mechanism in which the method called by an object gets associated by name in runtime. Late binding happens when virtual keyword is used in member function declaration.

Mechanism of Late Binding

C++ implementation of virtual functions uses a special form of late binding known as virtual table (VTable). When a class declares a virtual member function, most of the compilers add a hidden member variable that represents a pointer to Virtual Method Table (VMT or VTable). We will call this pointer as vptr. This table represents an array of pointers to virtual functions. At compile-time, there is no information about which function will be called. At runtime, pointers from Virtual Method Table will point to right functions.

Look on the following example:

class A
{
public:
	virtual void function1() {};
	virtual void function2() {};
};

class B : public A
{
public:
	virtual void function1() {};
};

class C : public A
{
public:
	virtual void function2() {};
};

When an object of any class is created, it has its own pointer to VMT:

VTable

When a function is called from an object, it will look in the corresponding VMT of that object.

Virtual Destructor

Destructor is called when an object is destroyed. C++ provides a default destructor for all the classes. However, sometimes there is a need to create your own destructor. It can be done in the case you need to deallocate memory, free a resource etc.

When you have a hierarchy of classes, it is strongly recommended to use virtual destructors. Declaration of Virtual Destructor looks in the following way:

virtual ~ClassName()

Why to use virtual destructors?

Upcasting without Virtual Destructor

Look on the following example:

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

class B : public A
{
public:
	~B()
	{
		cout << "B class destructor" << endl;
	}
};

int main()
{
	A* a = new B;
	delete a;
}

As you can see, pointer “a” points to an object of type B. When “a” is deleted, only the destructor of base class will be called. This means, that the object of a derived class will not be destroyed properly.

This problem is easily resolved with Virtual Destructor.

Upcasting with Virtual Destructor

Try to modify previous example by changing the destructor of base class to virtual (upcasting):

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

class B : public A
{
public:
	~B()
	{
		cout << "B class destructor" << endl;
	}
};

int main()
{
	A* a = new B;
	delete a;
}

When base class destructor is virtual, the derived class destructor is called first and after this, base class destructor is called:

B class destructor
Base class destructor

Abstract Class and Pure Virtual Function

Translate »