All are familiar with what a virtual function is; a member function of a class which can be overridden by any class which derives from it. To put it in even simpler words, member function that is declared with the keyword virtual .Before we have a peep into how a virtual function works lets have a brisk overview of what a virtual function is.
In case of regular member function the function to be called is resolved at compile time itself depending upon the type of the pointer used to call the object’s function. But with virtual function the function call is not based on the type of the pointer used to call the object’s function but solely on the object it points to. This happens dynamically at the run time using virtual tables & Virtual table pointers. Feeling bit confused? Let’s resolve it with an example.Take a look at the following class inheritance:-
class Base
{
private:
public:
void output(){cout<<”Base Output!!\n”; }
};
class Derived:Public Base
{
private:
public:
void output(){cout<<”Derived Output!!\n”;}
};
Notice here that the functions are non virtual and have identical function names.
Now let’s check the output for the following codes.
int main()
{
Base *pB=new derived; //Base Pointer pointing to Derived object
pB->output();
return 0;
}
Output:-
Base Output!!
Press any key to continue
Note that the Object is of the type derived where as the pointer referencing it is of the type Base.
Now as I am calling the output function from the base pointer, even though it points to a derived object, the base function is invoked. This is because during the compilation the base::output() function is statically typed to the base class function call.
To prevent this from happening we insert a virtual keyword before the out put function in the base class…
virtual void output(){cout<<”Base Output!!\n”;}
Now the output becomes:-
Derived Output!!
Press any key to continue
Here there is no static typing. The trick here is an implementation of a new technique involving virtual tables and virtual pointers for implementing dynamic binding.
Take for example a class which has 10 virtual functions. The first thing the compiler does is to create a virtual table (vtable) exclusively for that class with 10 entries where each entry holds a memory address where the corresponding 10 virtual function are implemented. This can be visualized as an array of function pointers as follows:-
className::__vtable[10]={&Base::v0,
&Base::v1,
&Base::v2,
&Base::v3,
&Base::v4,
.
.
.
&Base::v10
};
The point here is, when ever this class is inherited, a new virtual table is created for the derived class and if any of the virtual functions are overridden the function pointers in the new vtable will be overwritten with the new address which points to the new function implementation. Do keep in mind that for every class which implements/inherit virtual functions will have only 1 vtable per class.
Now you know that the class with virtual functions has a vtable and you create an object of that particular class. Some thing interesting happens here also. A new virtual pointer has been inserted into the class structure and is a part of every object created from that class. This virtual pointer points to the vtable of the corresponding class. So if you create 1000 objects of the class XYZ each object will have 1 virtual pointer and all of these 1000 pointers point to a single vtable owned by class XYZ. The class modification by the compiler and virtual pointer insertion into objects are hidden from the programmer. It can be visualized as an invisible data member being inserted into the class structure which points to the class’s vtable. Some thing like this:-
class Base {
public:
…
FunctionPtr* __vptr; //Inserted by compiler
//which points to vtable
…
};
The compiler also inserts a constructor modification so that when ever a new object is instantiated the newly inserted virtual pointer will be initialized to the starting address of the vtable owned by that class.Base
Base::Base() :__vptr(&Base::__vtable[0])
{
//Base class constructor initializing
//virtual pointer__vptr
}
Now you know what all extra code insertions are done by compiler to a class possessing virtual functions, its time to see the mechanism involved in a virtual function call. It involves just 3 steps-’Fetch-Fetch-Call’
Fetch1->Gets the Virtual pointer from the object and load it into the registry.
Fetch2->Gets the function pointer address into the registry from the Vtable
Call ->Call the function located at the address in the registry
Fetch1 Loads the Virtual pointer from the object into a registry. Now with this pointer we locate the vtable. In fetch2 the aim is to retrieve the function’s address from the vtable. For example if you want function no.3 from the v table we can calculate it by:
VirtualPointerValue+3*(size of function pointer)
This will return you the address where the function implementation is- load this information into a register. Now it’s the last step-call the code at the location specified by the function pointer in the register to see your virtual function in action.
Related Reading:-