C++ – Virtual Mechanism in C++

Hello Friends,

Today, in this article we will discuss, how Virtual mechanism is being handled in compiler level .

The virtual mechanism mostly used to accomplish the dynamic polymorphism, which we discusses in one of the previous blog C++ – Dynamic Polymorphism.

Let’s go through the following example.

We have a class, named “house_address” as a base class with functions to show the plot number, city name and house name. We have also 2 derived classes “house_x” and “house_y” derived from “house_address” class, inside “house_x” we did override all the members available in base class and in “house_y”, we did the same except member city name.

OutPut:

plot_number – 111

house_name – X

city – pune

plot_number – 222

house_name – Y

city – bangalore

In the above example, as class x and y are derived from class house address, their address can be stored in array of house address objects. It is like storing the derived class object in a base class pointer. So as the dynamic polymorphism works, the output is expected .

When we create any class, which has derived functions or derived from a base class, which has virtual function, the compiler creates a unique VTABLE for that class (e.g: below diagram)

blog_
Figure 1 : C++_Vtable description

In the virtual table compiler places all the address of virtual functions declared in the class or in its base class . If user won’t override the function declared virtual on the base class , compiler will put the address of  base class version for that function (As seen In the above example , house_y didn’t override the plot_number() function , so base class version is available in the VTABLE of house_y) . Then it places the VPTR into the classes . The VPTR must be initialized to point to the starting address of the VTABLE . This initialization part happens in constructor, which we will cover in our next blog.

So when user calls a virtual method through base class pointer, the compiler performs the below operations.

The compiler starts with the base class pointer (above example house_address pointer), which points to the starting address of the object.All the objects have their VPTR stored at the same place, At the beginning of the object.So the compiler fetches the VPTR out of the object, by taking the first word-size from the this pointer.                                                                        The VPTR points to the starting address of the VTABLE . And in the VTABLE, all the virtual functions are placed in same order irrespective of specific type of the object (above e.g plot_number(), house_number(), city_name()).So when the call container[0]->house_name(); happens, the compiler knows the function is located at VPTR+1 irrespective of the object. So instead of calling the absolute address of house_name() function , compiler generates the codes which indicate “call the function at VPTR+1”.The fetching the actual VPTR occurs at run time and this mechanism is called run-time binding .

Initializing the VPTR

*Objects with only one VPTR .                                                                                            When an object is created which has virtual function, the VPTR must be initialized to point to the proper VTABLE. This must be done before any call happens to virtual functions. So the best place to do this is Constructor .The compiler secretly insert code to the beginning of the constructor which initialize the VPTR irrespective of user defined or default constructor.

In case of inheritance, When user creates a object, all the base class constructors should be called before the constructor of that class. As we discuss the initialization of VPTR happens in the constructor.

The constructor only know that it is of current type. It is ignorant of the fact that, whether it is a base class or derived class. It generates code to initialize the VPTR to its VTABLE. The VPTR remains initialized to that VTABLE, for the rest of object’s life time unless this is not the last constructor call. If a more derived constructor is called afterwards, that constructor sets the VPTR to its VTABLE and so on until the last constructor finishes. So in this manner the VPTR points to the appropriate VTABLE at the end because the order of constructor calls happens from top to bottom .
So if we call virtual function inside a constructor , the local version of the function is called .

Thanks for reading 🙂

Keep reading, share your thoughts, experiences. Feel free to contact us to discuss more. If you have any suggestion / feedback / doubt, you are most welcome.

Stay tuned on Knowledge-Junction, will come up with more such articles .

Advertisements

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.