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

155 comments to 12.5 — The virtual table

  • krishna Chaitanya

    Thanks Alex for nice explanation.

    I have one doubt.
    As per your explanation “when a object of type Base
    is created, *__vptr is set to point to the virtual
    table for Base.”.

    But if I create 3 objects of type Base, as per your
    statement *__vptr is set to point to the virtual
    table for Base 3 times. But what is the need of
    setting __*vptr 3 times? Virtual table address
    should be same for all the 3 times.

    • Sumit

      “vptr” cannot be static because if it were, it would be shared by all( as you said)
      but when a base class object is made to instantiate a derived class object, the “vptr” then points to the v-table of the derived.therefore we need the vptr to point to different v-tables as per the context.

      therefore vptr is not shared by objects(static), else they would had already done that 🙂
      PS: v-tables are static for a class

  • sirius

    very good explanation..
    best

  • Sidharth

    Good article….thanks a bunch.

  • Senthil

    Excellent explanation

  • Dipak

    Very well explained. Thanks a lot.

  • Bala

    I was waiting for this kind of explanation such a long time. Thanks a lot ALEX

  • Shyam

    Very Good Explanation, this helped me alot to understand virtual table. I came across one query. Suppose I have a base class with non virtual function func1(), and virtual function func2(). I derived a class from this base class and this derived class has one non virtual function func3() and overrided virtual function func2(), than what would be the order of functions in virtual table of derived class?

  • Sumit

    Thanks so much!!! really the best explaination I came across.
    Can anyone explain to me, why a derived class pointer cannot point to a base class object. Why does it result in compiler error. The derived class object has everything the base is supposed to have?
    Thanks again!

    • Shyam

      Agreed, but if you pass this derived class pointer in any function, and this pointer access the derived member, than what would happen if you pass base class object via derived class pointer ?

    • A derived class always has all the functionality of a base class, whereas the converse is not true. So if you have a base pointer, whether you set it to a base class or a derived class, you’re guaranteed the functionality in the base class is present and can be accessed through the base pointer.

      However, if you have a derived pointer, what happens when you set it to point at a base class and then try and access something that only exists in the derived class? It wouldn’t know what to do.

  • Siva Prasad. S

    This is really the perfect way of explaining V-Table mechanisam. Every C++ programmer should visit this topic.

    But, i have one doubt. As it was specified, vptr is initialized when the instance of the class is created. But, if
    the base calss is an Abstarct Class, then there is no way that an instance will be created for that class.
    So, how the vptr of an Abstract Base class is initialized?

    • Hanumanth

      Abstract class cannot create object. Creating a pointer of abstract base class can only point to derived classes. So, the _vptr can in any case will point to only derived class vtable.

  • Prakash Agarwal

    This is by far the most clear and non-confusing explanation on V-Tables I have come through. I was searching for something like this for such a long time. Thanks to all who contributed in this. Good Job friends. Keep it up.

  • M V M Murali Krishna

    This is really explained very well with good exampls.

  • My concepts are not clear about the virtual tables which the compiler creates, well by reading this article, n ow it’s perfectly clear.

    Thnks a lot to the original author.

  • Really very good explanation.But still I have a doubt.The vtable is constructed at the compile time. Then how can it know the base pointer is pointed to some derived object and how can it calls the functions of that class.
    I think the virtual table contains 2 more entries reserved for RTTI(Run time type identifier) and destructor.
    I think RTTI do this operation to specify the base class pointer is pointing to some other derived class or not.

    Please give me explanation.

    • You are incorrect. The key is the following line: “When a class object is created, *__vptr is set to point to the virtual table for that class”

      The virtual tables are constructed at compile time for each class, but the *__vptr pointer is set at run time based on what type of class is actually being instantiated.

  • It is really good explanation.Thank you

  • DSK

    Thanks for the detailed and clear explanation!!

  • Harish

    [/code]I like this explaination, better than wikipedia[/code]

  • Lotfi

    Very simple and concise explanation of VTables. Thanks.

    What about multiple inheritance?
    And what about single inheritance but with multiple interface implementation (for the C++ CLI case)?

    • Alex

      Multiple inheritance gets a little weird. Let’s say you have three classes: B1, B2, and Multi (which is derived from both B1 and B2). Multi would have two __vptrs -- the first one points to the virtual table for B1, and the second to the virtual table for B2. The virtual functions in Multi will be appended to the virtual table of one of the base classes (probably B1). The vtables for multiple inheritance aren’t quite the same as the ones in the single inheritance case -- for example, they typically contain some additional data called a “thunk” that is used to fix up the *this pointer before the appropriate virtual function is called.

      In C++, inheriting multiple interfaces is still multiple inheritance.

  • aman mittal

    This learning material about virtual table is best according to me. I am searching about virtual table from a long time and i found this fulfills my requirements.

  • alex

    Congratulations for the clear explanation!
    But I still have a doubt… I took your code and made some changes on it to show you something. Look:

    I thought this way: once D1::function2() isn’t at the VTable of D1, cause it’s not virtual, and it’s also not in the scope of Base class, the only function2() *pb can see is the Base::function2(), inherited from the own base.

    But the result of this code is this:

    How can this be possible?

    • This brings up an interesting point. Once a function is marked as virtual, it is considered virtual from that point on, regardless of whether the virtual keyword is used in derived classes or not.

      Consider the following example:

      The answer is it prints D3. Because go() was declared as virtual in Base, it’s considered virtual in Base, D1, D2, and D3. Thus pBase->go() resolves all the way up to D3::go() in this case.

  • avinash

    Very clear explanation .. thnxx …

  • wlblmz

    good explanation, much better than wikipedia’s

  • Pramod

    very nice information.

  • Surender A

    This is Really very good.

  • Suresh

    Its really a lucid explanation. thanks a lot.

  • Kiran

    Thanks!!..
    This is the Best explanation on Vtable…..Its absolutely clear to understand.

  • Purna Gaddam

    Vere good info. Can you provide information on how V-table is generated for Virtual Destructors.?

    Thanks in advance,

    Thanks Much,
    Purna.

    • Alex

      Virtual destructors work exactly the same way as virtual functions -- they have an entry in the virtual table that gets called when the object is destructed.

  • Eli

    Thank you…this is the best explanation of vtable I have ever seen!!

  • Rag

    Good one!!!! Crisp and Clear.
    Thanks

  • Naseer

    Thank you ! This is by far the most clear explanation of vtables I have found.

Leave a Comment

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