Virtual Function

Function is a virtual function when the virtual keyword is added in the beginning of function declaration.
virtual void display();
virtual keyword is required in declaration. In function definition, virtual keyword is not required.

When you want to override(redefine) the function in derived class, then virtual function is required. This means virtual function works only when inheritance is involved. Let us understand with the help of an example.

class shape {
public:
virtual void draw() {}
virtual void func() {}
};

class rectangle: public shape {
public:
void draw() {
cout << “Draw rectangle” << endl;
}
};

This is very basic example. In this, we have created one base class shape and one derived class rectangle. When we have to draw any shape, shape class does not know what to draw. Therefore, its function definition is empty. Rectangle class know how to draw a rectangle because it has all the parameters required to draw a rectangle. Hence, we have to override the draw function.

Let us understand how to call virtual function in the main function.

int main() {
  shape* s1 = new shape();
    shape* s2 = new rectangle();
    s1->draw();
    s2->draw();
    s2->func();
    return 0;
}

In the above main function, upcasting is done in 2nd line i.e. taking the address of derived class object and assigning it to base class pointer and it is fully safe and no explicit casting is required as well.

When we call draw function from s1 object, draw function of shape is called since it is a shape class object.

When we call draw function from s2, draw function of rectangle is called. If it was not a virtual function, then draw function of shape class was called.

When we call func from s2, func function of shape is called since it is not overridden so it will call its base class i.e. shape.

In virtual function, late binding happens which is called dynamic polymorphism. Let us understand how internally virtual function works.

  • Whenever compiler see a virtual function in the class, it creates a virtual table called VTABLE for a class and insert vptr in the class.
  • Compilers inserts the address of virtual function(s) of the particular in the VTABLE.
  • Address of virtual function are stored in the order it is declared in a class.
  • To use VTABLE, vptr is initialized in the constructor of class when the object is created.
  • VTABLE is inherited from its base class.

Based on above points, let us try to create a VTABLE for shape and rectangle object.

VTABLE for Shape class object
VTABLE for Rectangle class object

When rectangle object is created, its vptr is initialized inside the constructor and points to VTABLE of rectangle class. Similarly for the shape object.

vptr of shape class object is pointing to VTABLE of shape class. It has two virtual function viz. draw and func of shape class.

vptr of rectangle class object is pointing to VTABLE of rectangle class. As VTABLE is inherited from its base class. So shape class VTABLE is copied to derived class but when compiler sees that draw function is overridden, its updates in VTABLE and for func, it remain as it is since it is not overridden. So finally, it will have two virtual function viz. draw of rectangle class and func of shape class.

This is how dynamic polymorphism works i.e. function call is decided at the run time based on type of object. Like in the above example, s2 object is created and its address is assigned to base class pointer. So when draw function is called, vptr of exact object i.e. rectangle is used to get the address of VTABLE and call the draw function.

Important points:
You cannot overload the function using virtual keyword i.e. two functions of same signature but one is virtual inside the same class is not possible.

Virtual nature is inherited to its derived classes i.e. we do not have to write virtual keyword for the derived class function. Derived class function is automatically becomes virtual function if its base class function of same signature is virtual.

Late binding mechanism works only when we use the address of base class like you see in the main function. if you simply create rectangle object and calls draw function, then late binding mechanism will not come in to picture as compiler knows the exact object and will bind it statically which is also called early binding.

Mostly in all compilers, vptr is the first data member of class so that when virtual function is called from the object, it can be easily de-referenced.

Class with virtual function(s) is called polymorphic class.

vptr increase the size of an object as it is part of an object.

VTABLE is per class and vptr is per object.

Related posts