- What is a Virtual Function in C++?
- C++ Virtual function is a Class member function used with Inheritance in C++ to achieve Runtime Polymorphism.
- We know Polymorphism means functions with the same name but different arguments. In Runtime Polymorphism Parent and Child classes have functions with the same name and also the same arguments which is called Overriding.
- Base class functions are prepended with the keyword virtual so that they can be overridden in child classes to add more functionality.
- The difference between virtual and non-virtual is
- Call to non-virtual functions resolved at compile time based on the type of Object pointer/Reference on which it is called.
- Call to virtual functions resolved at runtime based on the actual object to which the pointer/reference is pointing.
- 1 Runtime Polymorphism
- Before going to Virtual Function, let's discuss more about the Runtime Polymorphism with some example
- Runtime Polymorphism exists because in C++ Parent class pointer or reference can point to a child class object.
- Check the below code and read comments inside the code for a better understanding. This will explain how Runtime Polymorphism works in C++.
#include <iostream>
using namespace std;
//This is the Base class for all Food dishes, contatins basic functions for a food order
//In this class all functions are prepended with prefix virtual to acheive Runtime Polymorphism
class FoodDish {
public:
virtual void GetIngrdients() {
cout<<"This is base class , Geeting basic ingredients."<<endl;
}
virtual void Cook() {
cout<<"This is base class , just boiling."<<endl;
}
virtual void PackFood() {
cout<<"This is base class , don't know how to pack food."<<endl;
}
};
//This is Pizza class derviced from base class FoodDish, which override base class functions to fulfill Pizza order
class Pizza : public FoodDish {
public:
//override Base class function
void GetIngrdients() override{
cout<<"Geeting ingredients for Pizza."<<endl;
}
void Cook() override{
cout<<"Preparing Pizza."<<endl;
}
void PackFood() override {
cout<<"Packing Pizza."<<endl;
}
};
//This is Pizza class derviced from base class FoodDish, which override base class functions to fulfill Burger order
class Burger : public FoodDish {
public:
void GetIngrdients() override{
cout<<"Geeting ingredients for Burger."<<endl;
}
void Cook() override{
cout<<"Preparing Burger."<<endl;
}
void PackFood() override{
cout<<"Packing Burger."<<endl;
}
};
//This class is responsible for takong food orders and prepare food and packing
class FoodFactory {
public:
//Food Items available
enum FoodItem : uint8_t {
kPizza = 1,
KBurger
};
//This is public function to take order, call this with Enum arguement FoodItem, It will prepare and delive food ordered
//Here we are using Runtime Polymorphism
void TakeFoodOrder(FoodItem item) {
//Base class pointer
FoodDish *food_dish = nullptr;
switch (item)
{
case FoodItem::kPizza:
// new Pizza object created and assigned to Base class pointer
food_dish = new Pizza();
break;
case FoodItem::KBurger :
// new Burger object created and assigned to Base class pointer
food_dish = new Burger();
break;
default:
break;
}
if(food_dish != nullptr) {
/*
* PrepareFood function called with Base class pointer but it points to Object of FoodItem which is ordered.
* This function calls specific functions of ordered FoodDish(Pizza, Burger....)
*
*/
PrepareFood(*food_dish);
}
}
private :
/* This is private function to prepare food for correct food order.
* FoodFactory class call this function to prepare any food dish which is subclass of FoodDish.
* Functions(GetIngrdients, Cook, PackFood) of respective FoodDish(Pizza, Burger..) will be called to prepare
* right food even though arguent if FoodDish. This will be done by Runtime Polymorphism.
* If we don't have Runtime Polymorphism , we need to have multpile overloaded functions for each FoodDish like
* PrepareFood(Pizza &pizza), PrepareFood(Burger &burger).....
*/
void PrepareFood(FoodDish &dish) {
dish.GetIngrdients();
dish.Cook();
dish.PackFood();
}
};
int main() {
FoodFactory factory;
factory.TakeFoodOrder(FoodFactory::FoodItem::kPizza);
factory.TakeFoodOrder(FoodFactory::FoodItem::KBurger);
}
- This program will give the below result when the virtual keyword is prepended to base class functions. Calls to virtual functions resolve at runtime
Geeting ingredients for Pizza.
Preparing Pizza.
Packing Pizza.
Geeting ingredients for Burger.
Preparing Burger.
Packing Burger.
- This program will give the below result when the no virtual keyword is prepended to base class functions. Calls to virtual functions resolve at compile time based on the type of pointer or reference on which function is called, base class FoodDish in this case
This is base class , Geeting basic ingredients.
This is base class , just boiling.
This is base class , don't know how to pack food.
This is base class , Geeting basic ingredients.
This is base class , just boiling.
This is base class , don't know how to pack food.
- 2 How Runtime Polymorphism works in the background
- For each base class and for all its child classes a global Virtual table will be created at compile time.
- Each entry of the Virtual table is the function pointer to the respective virtual function implementation in the specific class.
- Virtual table contains entries as below
- For the Base class each entry is a function with the virtual keyword prepended
- For the child class each entry is an overriding version of the virtual function in the derived class
- Virtual tables will occupy in Data section of RAM.
- For the base class and for all its child classes a member variable with the name vptr will be added, which is a pointer points to the respective vtable of the class.
- Below is a picture of vtable for each class

Note: If a Child has not overridden a virtual function(no implementation of a base class function), then vtable entry points to address of base class function
- 3 Limitations of Virtual functions
- virtual functions are slow as they will be resolved at runtime, the run time system has to run additional code for that.
- virtual functions occupy the Data section of RAM in the system and are never freed(maybe freed when the library or application module containing the function is unloaded from RAM)
👍Thankyou
Nice
ReplyDelete