Search

12.5 — The virtual table

To implement virtual functions, C++ uses a special form of late binding known as the virtual table. The virtual table is a lookup table of functions used to resolve function calls in a dynamic/late binding manner. The virtual table sometimes goes by other names, such as “vtable”, “virtual function table”, “virtual method table”, or “dispatch table”.

Because knowing how the virtual table works is not necessary to use virtual functions, this section can be considered optional reading.

The virtual table is actually quite simple, though it’s a little complex to describe in words. First, every class that uses virtual functions (or is derived from a class that uses virtual functions) is given its own virtual table. This table is simply a static array that the compiler sets up at compile time. A virtual table contains one entry for each virtual function that can be called by objects of the class. Each entry in this table is simply a function pointer that points to the most-derived function accessible by that class.

Second, the compiler also adds a hidden pointer to the base class, which we will call *__vptr. *__vptr is set (automatically) when a class instance is created so that it points to the virtual table for that class. Unlike the *this pointer, which is actually a function parameter used by the compiler to resolve self-references, *__vptr is a real pointer. Consequently, it makes each class object allocated bigger by the size of one pointer. It also means that *__vptr is inherited by derived classes, which is important.

By now, you’re probably confused as to how these things all fit together, so let’s take a look at a simple example:

Because there are 3 classes here, the compiler will set up 3 virtual tables: one for Base, one for D1, and one for D2.

The compiler also adds a hidden pointer to the most base class that uses virtual functions. Although the compiler does this automatically, we’ll put it in the next example just to show where it’s added:

When a class object is created, *__vptr is set to point to the virtual table for that class. For example, when a object of type Base is created, *__vptr is set to point to the virtual table for Base. When objects of type D1 or D2 are constructed, *__vptr is set to point to the virtual table for D1 or D2 respectively.

Now, let’s talk about how these virtual tables are filled out. Because there are only two virtual functions here, each virtual table will have two entries (one for function1(), and one for function2()). Remember that when these virtual tables are filled out, each entry is filled out with the most-derived function an object of that class type can call.

The virtual table for Base objects is simple. An object of type Base can only access the members of Base. Base has no access to D1 or D2 functions. Consequently, the entry for function1 points to Base::function1(), and the entry for function2 points to Base::function2().

The virtual table for D1 is slightly more complex. An object of type D1 can access members of both D1 and Base. However, D1 has overridden function1(), making D1::function1() more derived than Base::function1(). Consequently, the entry for function1 points to D1::function1(). D1 hasn’t overridden function2(), so the entry for function2 will point to Base::function2().

The virtual table for D2 is similar to D1, except the entry for function1 points to Base::function1(), and the entry for function2 points to D2::function2().

Here’s a picture of this graphically:

Although this diagram is kind of crazy looking, it’s really quite simple: the *__vptr in each class points to the virtual table for that class. The entries in the virtual table point to the most-derived version of the function objects of that class are allowed to call.

So consider what happens when we create an object of type D1:

Because d1 is a D1 object, d1 has its *__vptr set to the D1 virtual table.

Now, let’s set a base pointer to D1:

Note that because dPtr is a base pointer, it only points to the Base portion of d1. However, also note that *__vptr is in the Base portion of the class, so dPtr has access to this pointer. Finally, note that dPtr->__vptr points to the D1 virtual table! Consequently, even though dPtr is of type Base, it still has access to D1’s virtual table (through __vptr).

So what happens when we try to call dPtr->function1()?

First, the program recognizes that function1() is a virtual function. Second, the program uses dPtr->__vptr to get to D1’s virtual table. Third, it looks up which version of function1() to call in D1’s virtual table. This has been set to D1::function1(). Therefore, dPtr->function1() resolves to D1::function1()!

Now, you might be saying, “But what if Base really pointed to a Base object instead of a D1 object. Would it still call D1::function1()?”. The answer is no.

In this case, when b is created, __vptr points to Base’s virtual table, not D1’s virtual table. Consequently, bPtr->__vptr will also be pointing to Base’s virtual table. Base’s virtual table entry for function1() points to Base::function1(). Thus, bPtr->function1() resolves to Base::function1(), which is the most-derived version of function1() that a Base object should be able to call.

By using these tables, the compiler and program are able to ensure function calls resolve to the appropriate virtual function, even if you’re only using a pointer or reference to a base class!

Calling a virtual function is slower than calling a non-virtual function for a couple of reasons: First, we have to use the *__vptr to get to the appropriate virtual table. Second, we have to index the virtual table to find the correct function to call. Only then can we call the function. As a result, we have to do 3 operations to find the function to call, as opposed to 2 operations for a normal indirect function call, or one operation for a direct function call. However, with modern computers, this added time is usually fairly insignificant.

Also as a reminder, any class that uses virtual functions has a __vptr, and thus each object of that class will be bigger by one pointer. Virtual functions are powerful, but they do have a performance cost.

12.6 -- Pure virtual functions, abstract base classes, and interface classes
Index
12.4 -- Early binding and late binding

156 comments to 12.5 — The virtual table

  • Thanks! Best explanation on v-table I have come across. May be make this as wikipedia entry and replace the existing one! This is far better than that!

  • cpp-learner

    Thank you, thank you, thank you. Absolutely the best tutorial written for anything in human history.

  • Ravikumar

    Heading : Non virtual function of base class is getting executed though it is overridden
    in the derived class.

    Please find the code sample below.

    class vehicle
    {
    public:
    virtual void speed()
    {
    cout << "In base speed" << "\n";
    }

    virtual void maintain()
    {
    cout << "In base maintain" << "\n";
    }

    void value()
    {
    cout << "In base value" << "\n";
    }

    };

    class wheel4 : public vehicle
    {
    public:
    virtual void speed()
    {
    cout << "In 4wheel speed" << "\n";
    }

    virtual void maintain()
    {
    cout << "In 4wheel maintain" << "\n";
    }

    void value()
    {
    cout << "In wheel4 value" <value();
    }
    After the execution of ptr->value(), the function present in the class “vehicle” is
    getting executed. As per my understanding the “value” present in wheel4 should
    be executed.

    What is the reason for this?

    • Soumya

      Non virtual function can’t be overridden in derived class. only speed and manitain method is overridden in wheel4 class.

      for that reason it is printing vehicle’s class value method output.

    • Deepu Abraham K

      As Alex had stated in the above diagram,

      When you do
      vehicle* vobj = new wheel4;
      here what happens is *ONLY* the *__vptr of vehicle class will get updated with the vtable of wheel4.

      remember that you have only one function in the virtual table i.e, void speed()

      if you want to print “In wheel4 value” make the void value() function in the vehicle class as virtual void value() by doing this you are adding this function into the virtual table..

      the crux of this revolves around the *__vptr getting filled by the vtable pointer.This is how c++ obtains the dynamism which it claims.

      Hope this clear the air !

  • MBM

    Hi Alex,
    It is a very nice explanation.
    I have one query: If *__vptr value is same for all instances of a class. why it can not be “static” (initialized only once per class) and why it needs to be replicated in all instances (which adds additional pointer size to all instances).

    • Soumya

      Hi

      it can’t be static because it will change the address according to the allocation.

      C1 *cClass= new C1();
      D1 *dClass= new D1();
      Base *pClass = &dClass;
      Base *p1Class= &cClass;

      vptr of pClass instance is pointing D1 vtable
      vptr of p1Class instance is pointing C1 vtable

  • Abhinav Raghunandan

    Truly awesome !!!! The most simple and precise explanation .

    -Student of IIT Madras

  • Giri

    This diagram is all what’s needed to explain the whole story. Thank you very much.

  • Vijay

    Wonderful explaination. Can you explain diamond (virtual) inheritance as well ?

  • priyanka

    Hey really good explanation!!!Thanks a lot!!

  • lalit

    ohhhh… its really too good. explanation thank u very much…

  • HC Reddy

    Thanks a lot…it is crisp, simple and straight

  • Uwe Schuster

    This makes the question: In which compilation unit the vtable of a class is placed by the compiler. For instance, if we have the case:

    most compilers will do somewhat like this: The vtable is placed in the object file with the definition of the first non-pure, non-inline, virtual function of the class (classAf.o in this example) with external linkage.

    But what if we have:

    useA1() and useA2() must have access to the vtable of class A, but where is it defined, since the compiler rule from previous example does not match here?

    In can be defined in both useA1.cpp and useA2.cpp, but than it must have static linkage.

    Right or do I miss something?

  • Sadiq

    It’s beyond being helpful, indeed. πŸ™‚

  • satya

    Thanks a Lot.
    This is by far the most clear explanation of V-table i ever read.

    Regards,
    Satya

  • kumar

    • Roger Gonsalves

      Here you are creating object of D2 and storing it in base class pointer ptr.
      Since there is no relation between D1 and D2, typecasting of ptr to D1 will lead to heap corruption.
      I came across this type of issue in my code.

  • Anil

    Its really good and simple to understand about Virtual function and VTable. Can you please explain the second step in your explanation [Index the virtual table to find the correct function to call].
    Thank you.

    • Alex

      How vtables are laid out and indexed is implementation dependent. Often the entries in the vtable occur in the same order as they are defined in the class, so the compiler can use the ordering of the virtual functions in the class as the index.

  • Ishdeep

    Great explanation. Many thanks.

  • Vijay Chulaki

    ALEX, Thanks a lot…for helping many of us to understand ‘vtables’.

    Q: can any one let me know if we can display the ‘vtable’ for a class? If yes, HOW?

    ref : ‘http://en.wikipedia.org/wiki/Virtual_method_table’. Here they are displaying the vtable for a class as below :

    >>>>>>>>>>>>>
    G++ 3.4.6 from GCC produces the following 32 bit memory layout for the object b2:[nb 1]

    b2:
    +0: pointer to virtual method table of B2
    +4: value of int_in_b2

    virtual method table of B2:
    +0: B2::f2()
    <<<<<<<<<<
    -thnx,
    Vijay Chulaki

  • Venkat

    Very nice explanation on Vtable..ThankQ
    but i have one basic doubt.
    we created appropriate object and compiled.
    Vtable and object creation(so *vptr is initialized) everything is done during compile time itself.and we clearly mentioned base pointer is pointed to derived obj.So what is the special thing that will happen during run time and why it called late binding.

    • Paras Jatkar

      Object allocation in the memory will be done at run time and assignment of that allocated memory address can be assigned only at Run time.
      This will happen at the Run time and hence called ‘Late binding’.

      Its a nice Explanation from the original author..
      Good Job! πŸ™‚

    • Alex

      The __vptr is set to the appropriate vtable at runtime (the vtables themselves are created at compile time)

      It’s called late binding because we are calling the most-derived function through a pointer (rather than making a direct function call).

  • manu

    Thank you very much.very nice article.

  • Prerana

    If a base class has 1 pure virtual function then what will be the corresponding entry in the
    vtable? will it be NULL?

    • Calista

      Yes, the vtable entry will be NULL. If you think about it, a pure virtual function in a class makes it abstract which means we can never instantiate the class - which means we can’t call that function directly or indirectly from any base\derived class objects (we can’t create base class objects anyway and in case of derived class, if you define the “pure virtual function” of base class then you have provided the implementation. And if you don’t - then the derived class in turn becomes an abstract class. And so it goes on and on.

      To cut it short - yes, it will have NULL. Then you might ask who is going to invoke the NULL function? Not me. No one can call it and it also wastes memory. So Microsoft came with its own invention for that, when you declare a class with __declspec(novtable) for abstract base classes - you are effectively saying - “I know what I am doing. I don’t want to declare the vtable for this abstract base class, since no one can instantiate an object of this class anyway. So please save some memory and donot construct the vtable. Thank you”.

      Also consider C# - to declare a class as abstract all you have to do is:
      “abstact class IAmIntuitiveAbstractClassDeclaration”

      Isn’t that intuitive instead of define virtual function, and then make that virtual function “pure” - = 0? I might have as well said “you can declare an abstract base class by making one of the virutal functions a zombie and declare it like this

      “virtual void laspseInDesign const = Zombie” Seems ad hoc to me.

    • Alex

      Yes, it could be 0, or it could be to a generic function that prints an error (sometimes this function is called __purecall).

      • Priya

        So does that mean, in the pictorial representation of vtable and classes, for base class in vTable instead of function1() we will have value 0. Please correct me if my understanding is not correct. OR vTable itself will not be there for Base class. If so, then how we will refer function2() of Base class?

        • Alex

          Assuming function1 was pure virtual, the vtable would still be there, but the pointer for function1() would either point to 0, or to whatever the generic function is that prints an error.

  • Vikas

    Simple and superb!!!!

  • satya

    This is very nice and stright farward article. Thanks to author.

  • dave

    where is the donation section….u deserve it! my prof cant do even close good explanation …

  • Anand

    Its a very good explanation I have ever seen

  • Santosh

    Kudos,

    I am very very thankful to the writer of this article. This is the best
    and nothing can be better than this.

    God bless you.

    Santosh

  • good atricle…….removes sonamt confusions……..thx. man

    -Prasanth

  • Arvind

    Very Nice article.
    Thanks for explaining such a difficult topic in such a simple manner.

  • Person who dont know much about c++ can also understand clearly by looking
    into this explaination. Really a good expln on vtable.

    Thanks…

  • kk

    ultimate explanation…good job

  • Avnish Tyagi

    gud one!

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter