Virtual Function in C++

Amit Kumar Parida
4 min readNov 6, 2022

Why to use Virtual Function?

Virtual functions are used to achieve dynamic polymorphism which is the ability to call the appropriate Derived class function using Base class pointer or reference at runtime.

How to use Virtual Function?

  • Declare function as virtual in Base class and override that function in Derived class. (Function signature should be same in Base and Derived class)
  • Declaring a function as virtual in Base class is enough. The same function need not to be declared virtual in Derived class.
  • Virtual functions should be accessed using pointer (*) or reference (&) of Base class type to achieve runtime polymorphism.

Additional notes:

  • Virtual functions cannot be static and cannot be a friend function of another class.
  • A class can have virtual destructor but can’t have virtual constructor.
  • The base class destructor must be virtual if you delete a derived class object through its base class pointer.
  • You should not call virtual functions either from constructors or destructors. If it seems necessary to do so, then the design is obviously wrong.
  • It is not necessary to override the virtual function in the derived class. If the virtual function is not overridden, then the original function defined in the base class is called.

What’s the difference between how virtual and non-virtual member functions are called?

Non-virtual member functions are resolved statically. That is, the member function is selected statically (at compile-time) based on the type of the pointer (or reference) to the object.

In contrast, virtual member functions are resolved dynamically (at run-time). That is, the member function is selected dynamically (at run-time) based on the type of the object, not the type of the pointer/reference to that object. This is called “dynamic binding”. See below section for more details.

How Virtual Function is implemented or how Dynamic Polymorphism is achieved in C++?

The way compilers handle virtual functions is to add a hidden member to each class if the class or its parent class has one or more virtual functions. The hidden member is called Virtual Pointer (vPtr). This vPtr points to an array of function pointers. Such an array is termed as Virtual function table (vTable). The vTable holds the addresses of the virtual functions declared in the class or parent class.

An object of a base class, for example, contains a pointer to a table of addresses of all the virtual functions for that class. An object of a derived class contains a pointer to a separate table of addresses. If the derived class provides a new definition of a base class virtual function, its vTable holds the address of the new function. If the derived class doesn’t redefine any base class virtual function, its vTable holds the address of the base class virtual function. If the derived class defines a new function and makes it virtual, its address is added to the vTable of derived class.

When we call a virtual function at runtime, the program looks at the object’s vPtr member to get the address of corresponding vTable and then goes to the vTable to find the appropriate virtual function address to execute it. For example, if we call the first virtual function defined in the class declaration, the program uses the first function address in the vTable array and execute the function that has that address, and so on.

To summarize, virtual functions are implemented using an array/table of function pointers, called the vTable. There is one entry in the table per each virtual function in the class. vTable is created by the constructor of the class at the compile time. When a derived class is constructed, its base class is constructed first which creates the base class vTable, then derived class vTable is created. If the derived class overrides any of the base class virtual functions, those entries in the derived class vTable are overwritten by the derived class constructor. This is why you should never call virtual functions from a constructor, and that’s because the vTable entries for the object may not have been set up by the derived class constructor yet. So, you might end up calling base class implementations of those virtual functions.

Virtual Pointer (vPtr):

  • vPtr holds the address of vTable.
  • vPtr is constructed and initialized in constructor.
  • vPtr is created in every class that has virtual function(s) or is derived from a class which has virtual function(s).
  • Every class has its own vPtr.
  • Every object of same class points to same vTable.

Virtual Table (vTable):

  • vTable is a static table which gets constructed at compile time.
  • Every class has its own vTable.
  • vTable store address (with some other info) of virtual functions of own class OR parent class.
  • Parent class vTable is copied to child class vTable and then if child class overrides its parent’s virtual function, that function address is replaced by the address of child class function, in the child class vTable.

Drawbacks of Virtual Functions:

  • Each object has its size increased by the amount needed to hold the vPtr.
  • For each class, the compiler creates a table of addresses of virtual functions.
  • For each function call, there’s an extra step of going to a table to look up an address.

Demo program:

Below program demonstrates almost all the use cases of virtual function.

--

--