c++virtual-functionsdynamic-bindingrun-time-polymorphism

How virtual keyword leads to dynamic binding?


I know the following

Compiler constructs a virtual table for every class containing at least one virtual function. It also adds a pointer(v_ptr) to the base class(supposing it has virtual function(s)) and the pointer gets inherited by every derived class. When an object of a class is created that same pointer is made to point to the virtual table of class the object belongs to.

Now if I'm not wrong all above occurs at compile time only. If so then considering following example how is virtual keyword leading to dynamic binding.

#include <iostream>
using namespace std;

class base {
    public:
        virtual void show()
        {
            cout << "base\n";
        }
};
 class derived:public base{
    public:
        void show()
        {
            cout << "derived\n";
        }
 };


int main()
{
    base* ptr;
    derived drv1;
    ptr = &drv1;
    ptr->show();
    return(0);
}

In the above code how does dynamic binding occurs at the statement ptr->show(); since I think all is known at compile time to bind the function. show() is called via ptr which points to the base of derv1 which will be containing v_ptr pointing to the virtual table of its class and hence compiler knows which show() to call at the compile time only.

NOTE - The base of derv1 means the portion that is inherited from base class.


Solution

  • In this line

    derived drv1;
    

    an instance of a class is created. For this purpose, the constructor of the class is executed. (In this example, all constructors are implicitly declared and defined, but this fact makes no difference.)

    1. The constructor of derived begins. It immediately calls the constructor of base.
    2. The constructor of base fills in the instance's virtual table pointer to point to base's virtual dispatch table.
    3. The constructor of derived resumes after base's constructor ends.
    4. At this point it changes the instance's virtual table pointer to point to derived's virtual dispatch table.

    The point is that the evolution of the instance happens at runtime, not at all at compile time.

    Of course, optimizations may reduce things down to a level that nothing of this process is visible in the generated assembly ("devirtualization").