Search code examples
c++functiongccvirtual

Virtual Function call at Runtime (std c++)


vtable is an overhead in all base/derived classes when a base class has a virtual function. vtable is supposed to contain an array of function pointers to these virtual functions. Also vtable is "one per class" as opposed to "one per object".

Now imagine an object of such a class being created. It'll get a fresh copy of virtual functions of the class in some memory location by the runtime. Since vtable is a collection of function pointers it'll be updated to reflect this. If another object of the same class is created then it'll again have a fresh copy of the virtual functions in some other memory location

Since vtable is "one per class" and not "one per instance" how will it point to correct location for different instances?


Solution

  • It's simple... the vftable itself is one-per-class, the pointer is one-per-instance. Two instances of the same type will have their vftable pointer pointing to the same location.

    class A
    {
       virtual void foo();
       virtual void goo();
    }
    
    class B : public A
    {
       virtual void foo();
    }
    

    In memory, you will have:

    vftable for A:  
    
    +----------+---------+
    |   0x01   |  0x02   |
    +----------+---------+
      &A::foo()  &A::goo()
    
    vftable for B:
    
    +----------+---------+
    |   0x11   |  0x12   |
    +----------+---------+
      &B::foo()  &A::goo()
    

    Assume you create two objects:

    A a;
    B b;
    

    a's first member will be:

    vftableptr: 0x01
    

    b's first member will be

    vftableptr: 0x11
    

    In general, polymorphism is implemented getting the address of the vftable, adding the function offset (for example, if we call goo(), the offset is 1), and jumping to that location. Since the objects are of different types, they will point to different locations, although the vftables (which are different) can contain similar members.

    IMPORTANT NOTE: values are bogus, the offset isn't 1 nor the addresses 0x01 etc., I chose them to make a point.