×

Virtual Functions and Runtime Polymorphism in C++

In this tutorial, we will explore more on virtual functions and runtime polymorphism in the most useful language C++.

A virtual function is a member function with the keyword virtual used in its declaration in the base class and redefined (Overridden) in the derived class. It instructs the compiler to conduct late binding, in which the compiler performs the function during runtime after matching the object with the appropriately called function. Runtime Polymorphism applies to this method.

The word "polymorphism" refers to the capacity to assume various forms. It happens when classes are arranged in a hierarchy and are all related to one another through inheritance. When we deconstruct polymorphism into "Poly - Many" and "morphism - Forms," it simply means displaying different traits in various contexts.

Virtual Functions and Runtime Polymorphism in C++

Keep in mind: Calling a virtual function in C++ refers to the fact that depending on the kind of object that called the function, a different function can be executed in its place.

The virtual call technique is forbidden in constructors since overriding from derived classes hasn't happened yet. Objects are constructed from the ground up or using a bottom-to-top methodology, it should be added.

Take the simple program that follows as an illustration of runtime polymorphism. The function of the derived class is called using a base class pointer, which is the most crucial aspect of the program to remember.

Virtual functions are supposed to be called based on the type of the object instance being pointed to or referenced, not the type of the pointer or reference.

In other words, runtime is when virtual function resolution occurs. In C++, a virtual function is used to choose the member function of a class at runtime. The identically named function in the derived class replaces the base class function.

Virtual function in C++: Syntax

Virtual functions are defined using the term virtual.

Class ClassName
 {
   public:
     virtual return FuncionName ( args. )
      {
        // Function definition
      }
 }

To help one comprehend, we'll now look at an example without using virtual function notions.

C++ Program:

// Using a C++ program, we can illustrate how to calculate the area of shapes without using virtual functions.
#include <iostream>
using namespace std;


// Base class
class Shape1 {
public:
	// constructed with parameters
	Shape1 ( int len, int wid )
	{
		length = len;
		width = wid;
	}
	int getArea ()
	{
		cout << "The parent class area is being called.\n";
		// When a user-defined function returns 1, it means "true."
		return 1;
	}


protected:
	int length, width;
};


// Derived class
class Square1 : public Shape1 {
public:
	Square1 ( int len = 0, int wid = 0 )
		: Shape1 ( len, wid )
	{
	} // Considering derived class constructor
	int getArea ()
	{
		cout << "Square area: " << length * width << '\n';
		return ( length * width );
	}
};
// Derived class
class Rectangle1 : public Shape1 {
public:
	Rectangle1 ( int len = 0, int wid = 0 )
		: Shape1 ( len, wid )
	{
	} // Considering derived class constructor
	int getArea ()
	{
		cout << "Rectangle area: " << length * width
			<< '\n';
		return ( length * width );
	}
};


int main ()
{
	Shape1* sp;


	// Making a square1 object for the child class
	Square1 sqr (5, 5);


	// Making a rectangle1 object for the child class
	Rectangle1 rect ( 4, 5 );
	sp = &sqr; // reference variable
	sp -> getArea ();
	sp  = &rect; // reference variable
	sp -> getArea ();


	return 0; // to verify that the code perform successfully.
}

Output:

The parent class area is being called.
The parent class area is being called.

In the Aforementioned Illustration:

It should have called the corresponding getArea() functions of the child classes, but instead, it calls the getArea() function specified in the base class. We save the address of each child class's Rectangle1 and Square1 object in sp, and then we call the getArea() function on it. This occurs as a result of static linkage, which means the compiler only sets the call to getArea() once, in the base class.

Example: A C++ programme that uses virtual functions to calculate the area of shapes

C++ Program:

// Using a virtual function, a C++ program will show users how to calculate the area of shapes.
#include <fstream>
#include <iostream>
using namespace std;


// Declaring Base class
class Shape1 {
public:
	// Using virtual constructor
	virtual void calculating ()
	{
		cout << "Area of your Shape ";
	}
	// preventing memory leaks by utilising a virtual destructor
	virtual ~Shape1 ()
	{
		cout << "Shape Destuctor Call\n";
	}
};


// Declaring Derived class
class Rectangle1 : public Shape1 {
public:
	int w, h, A;


	void calculating ()
	{
		cout << "Put Width of Rectangle in: ";
		cin >> w;


		cout << "Put Height of Rectangle in:";
		cin >> h;


		A = h * w;
		cout << "Area of Rectangle: " << A << "\n";
	}


	// A virtual destructor for each derived class
	virtual ~Rectangle1 ()
	{
		cout << "Rectangle Destuctor Call\n";
	}
};


// Declaring 2nd derived class
class Square1 : public Shape1 {
public:
	int s, A;


	void calculating ()
	{
		cout << "Put one side your of Square: ";
		cin >> s;


		A = s * s;
		cout << "Area of Square: " << A << "\n";
	}


// A virtual destructor for each derived class
	virtual ~Square1 ()
	{
		cout << "Square Destuctor Call\n";
	}
};


int main ()
{


	// base class pointer
	Shape1* Sp;
	Rectangle1 rect;


	// initializing of reference variable
	Sp = &rect;


	// calling Rectangle function
	Sp -> calculating ();
	Square1 sqr;


	// initializing of reference variable
	Sp = &sqr;


	// calling Square function
	Sp -> calculating ();


	// to verify that the code perform successfully
	return 0;
}

Output: (If the user puts 3, 12, 4 as three consecutive inputs)

Put Width of Rectangle in: 3
Put Height of Rectangle in:12
Area of Rectangle: 36
Put one side your of Square: 4
Area of Square: 16
Square Destuctor Call
Shape Destuctor Call
Rectangle Destuctor Call
Shape Destuctor Call

What is the goal?

  • Without even being aware of the type of derived class object, virtual functions enable us to compile a list of base class pointers and call any of the derived classes' methods.
  • Examples from Real Life to Help one Understand How Virtual Functions Are Implemented
  • Think about a company's employee management software.
  • Create a straightforward basic class called Employee in the code, then add virtual methods to it like raisesalary(), transfer(), and promotion().
  • The virtual functions that are included in the base class Employee may have different implementations for different employee kinds like Executives, Engineers, etc.
  • Without even understanding the type of employee, we just need to pass a list of employees anywhere in our full software and call the necessary functions.
  • For instance, by going through the list of employees repeatedly, we may quickly increase the salaries of all the employees.
  • We don't need to worry about the internal logic that each employee type may have because only that function would be run if raisesalary() was present for that employee type.

C++ Program:

// A virtual function's utility in a real-world context is demonstrated through a C++ program.
class Employee {
public:
	virtual void raise_salary()
	{
		// code of common raise salary 
	}


	virtual void promotion ()
	{
		// code of common promote 
	}
};


class Manager : public Employee {
	virtual void raise_salary ()
	{
		// Code for manager-specific salary increases that may also include an increase in manager-specific incentives
	}


	virtual void promotion ()
	{
		// Manager specific promotion
	}
};


// Likewise, there might be different kinds of workers.


/* To increase the salaries of all employees, we require a fairly straightforward function.
Empl[] is an array of pointers, and the actual pointed objects might be any kind of employees.
We made this function global to keep things simple even though it should ideally be in a class like Organization.*/


void globalRaiseSalary ( Employee* Empl [], int num )
{
	for ( int i = 0; i < num; i++ ) {
		// Polymorphic Call: Calls raise_salary()
		// according to the actual object, not
		// according to the type of pointer
		Empl [i] -> raise_salary();
	}
}
  • Many more operations on a list of employees can be carried out similarly to the 'globalRaiseSalary()' function even without understanding the type of the object instance.
  • Modern programming languages, like Java, maintain all methods virtual by default since virtual functions are so helpful.
  • What sort of runtime resolution does the compiler do?
  • To accomplish this, the compiler keeps two things in order:
  • vtable: A list of function pointers that is updated for each class.
  • vptr: An object instance-specific pointer to the vtable.
  • To use and maintain vptr, the compiler writes extra code twice.

1. Include code in all constructors. The vptr of the object being formed is set by this code. This code causes vptr to point to the class's vtable.

2. Code that calls polymorphic functions, such as bp->show() in the code above. Every time a polymorphic call is made, the compiler adds code to first check for vptr using a base class pointer or reference (In the above example, since the pointed or referred object is of a derived type, vptr of a derived class is accessed). Access to the derived class vtable is possible after retrieving the vptr. The address of the display() derived class method is obtained and invoked using vtable.

Is this the accepted practise for C++ run-time polymorphism implementation?

Although the C++ standards do not specify the specific implementation of runtime polymorphism, most compilers employ slight variations of the same fundamental model.


Related Topics

C++ Switch

In C++, an expression or variable can be tested against a range of constant values using a switch statement, which is a control flow statement. It offers a productive method...

4 minutes read.

C++ Socket Programming

In this world, computer networking has become very important for sharing of data. Every good programmer has some knowledge about computer networking. Socket programming is one of the critical topics...

6 minutes read.

Input Iterators in C++

What are input iterators? Input iterators are used in sequence for carrying out input operations where each value is read-only. It is pointed by the iterator and further incremented. All the iterators...

4 minutes read.

Compile Time Polymorphism in C++

What is Polymorphism? Polymorphism refers to the existence of various forms. Polymorphism can be simply defined as a message's capacity to be presented in multiple forms. One application of polymorphism in...

4 minutes read.

C++ Output Iterators

Iterators : Iterators serve as a link between algorithms and STL containers, allowing the data inside the container to be modified. They let you to iterate through the container, access and...

4 minutes read.

Observer Design Pattern in C++

The Observer design pattern is a behavioural design pattern that allows an object (known as the subject) to notify other objects (known as observers) when its state changes. This is...

3 minutes read.

C++ Interfaces

The C++ programming language provides programmers with a variety of capabilities and functions. It also enables object-oriented programming, which is essential while working on a project. It will be simple...

7 minutes read.

Assertions in C/C++

Assertions are the statements used to check presumptions which is made by the programmers. Example: Assertion is used to verify whether the malloc returned by the pointer is NULL or not. For...

4 minutes read.

C++ Virtual Destructor

In C++, a destructor is a class member function that is used to free up space or remove an object of the class that has gone out of scope. The...

4 minutes read.

C++ Writing to file

In file handling, write() function is used to write data into the file. The write() uses ofstream or fstream library to write into the file. Syntax file-stream-class   file-stream-object;   file-stream-object.write((char *)&var , sizeof (var)); The write() takes two arguments. The first argument is the address of variable var...

2 minutes read.

Print Table Using For-loop in C++

Multiplication Table In mathematics, a table is created by multiplying a certain number by all of the counting numbers, i.e., 1, 2, 3, 4, 5, 6, and so on. It is...

3 minutes read.

C++ Continue in for loop

Continue statement: Inside the loop, the continue statement is used to control the loop. C++ utilizes the continue keyword to implement the continue statement, which transfers the program's flow at the start...

4 minutes read.

Bitwise Operator vs Logical Operator

Bitwise Operator  Bitwise operators perform operations bit by bit on bits.The value is converted to abinary during operations like addition, subtraction, division, and so on. These operations are carried out at the...

3 minutes read.

How to implement map in C++

Part of the C++ STL is maps (Standard Template Library). Maps are associative containers that hold sorted key-value pairs, where each key is distinct and may only be added or...

4 minutes read.

Computing index using Pointers Returned by STL Functions in C++

In this tutorial we will learn how to compute index using pointers which returned by STL functions in C++. Many built-in C++ functions return pointers to memory places that provide...

2 minutes read.

User-defined literals in C++

Introduction to User-Defined Literals: User-defined literals, introduced in C++11, are a way to extend the C++ language to allow users to define their literal suffixes and the corresponding behavior. These suffixes...

7 minutes read.

Decltype type Specifier in C++

The primary use of C++ decltype is to inspect the declaration type of an entity in an expression. The auto keyword can declare a particular type of variable, whereas the...

4 minutes read.

Passing a Vector to a function in C++

A pointer is sent to the function when we feed it an array. However, there are two ways to pass a vector: Pass by Value Pass by Reference A copy of a vector...

3 minutes read.

C++ Type Casting

The type casting of variables in the C++ programming language will be covered in this section. The term "type casting" describes how software converts one data type to another. There...

9 minutes read.

Reverse a Number in C++

In this tutorial, you'll learn how to utilize a C++ program to reverse a number entered by a user at runtime. Because there are various ways to write a C++...

3 minutes read.