13

Does every object of virtual class have a pointer to vtable?

Or only the object of base class with virtual function has it?

Where did the vtable stored? code section or data section of process?

MainID
  • 29,070
  • 19
  • 57
  • 70

9 Answers9

19

All classes with a virtual method will have a single vtable that is shared by all objects of the class.

Each object instance will have a pointer to that vtable (that's how the vtable is found), typically called a vptr. The compiler implicitly generates code to initialize the vptr in the constructor.

Note that none of this is mandated by the C++ language - an implementation can handle virtual dispatch some other way if it wants. However, this is the implementation that is used by every compiler I'm familiar with. Stan Lippman's book, "Inside the C++ Object Model" describes how this works very nicely.

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • 2
    +1 And would you please explain why virtual pointer is per object, and not per class? Thank you. – Viet Mar 11 '13 at 07:11
  • 1
    @Viet You can think of the vPtr as a bootstrap to the runtime definition of an object. It is only AFTER the vPtr is set up that the object can know what its actual type is. In this notion, making a vPtr per class (static) does not make sense. Thinking about this another way, if an object does not need a vPtr then it must already know about its runtime definition during compile time which contradicts it being a dynamically resolved object. – Johnson Wong Mar 12 '14 at 06:57
14

Like someone else said, the C++ Standard does not mandate a virtual method table, but allows one to be used. I've done my tests using gcc and this code and one of the simplest possible scenario:

class Base {
public: 
    virtual void bark() { }
    int dont_do_ebo;
};

class Derived1 : public Base {
public:
    virtual void bark() { }
    int dont_do_ebo;
};

class Derived2 : public Base {
public:
    virtual void smile() { }
    int dont_do_ebo;
};

void use(Base* );

int main() {
    Base * b = new Derived1;
    use(b);

    Base * b1 = new Derived2;
    use(b1);
}

Added data-members to prevent the compiler to give the base-class a size-of of zero (it's known as the empty-base-class-optimization). This is the layout that GCC chose: (print using -fdump-class-hierarchy)

Vtable for Base
Base::_ZTV4Base: 3u entries
0     (int (*)(...))0
4     (int (*)(...))(& _ZTI4Base)
8     Base::bark

Class Base
   size=8 align=4
   base size=8 base align=4
Base (0xb7b578e8) 0
    vptr=((& Base::_ZTV4Base) + 8u)

Vtable for Derived1
Derived1::_ZTV8Derived1: 3u entries
0     (int (*)(...))0
4     (int (*)(...))(& _ZTI8Derived1)
8     Derived1::bark

Class Derived1
   size=12 align=4
   base size=12 base align=4
Derived1 (0xb7ad6400) 0
    vptr=((& Derived1::_ZTV8Derived1) + 8u)
  Base (0xb7b57ac8) 0
      primary-for Derived1 (0xb7ad6400)

Vtable for Derived2
Derived2::_ZTV8Derived2: 4u entries
0     (int (*)(...))0
4     (int (*)(...))(& _ZTI8Derived2)
8     Base::bark
12    Derived2::smile

Class Derived2
   size=12 align=4
   base size=12 base align=4
Derived2 (0xb7ad64c0) 0
    vptr=((& Derived2::_ZTV8Derived2) + 8u)
  Base (0xb7b57c30) 0
      primary-for Derived2 (0xb7ad64c0)

As you see each class has a vtable. The first two entries are special. The second one points to the RTTI data of the class. The first one - i knew it but forgot. It's got some use in more complicated cases. Well, as the layout shows, if you have an object of class Derived1, then the vptr (v-table-pointer) will point to the v-table of class Derived1 of course, which has exactly one entry for its function bark pointing to Derived1's version. Derived2's vptr points to Derived2's vtable, which has two entries. The other one is the new method that's added by it, smile. It repeats the entry for Base::bark, which will point to Base's version of the function of course, because it's the most derived version of it.

I've also dumped the tree that's generated by GCC after some optimizations are done (constructor inlined, ...), with -fdump-tree-optimized. The output is using GCC's middle-end language GIMPL which is front-end independent, indented into some C-like block structure:

;; Function virtual void Base::bark() (_ZN4Base4barkEv)
virtual void Base::bark() (this)
{
<bb 2>:
  return;
}

;; Function virtual void Derived1::bark() (_ZN8Derived14barkEv)
virtual void Derived1::bark() (this)
{
<bb 2>:
  return;
}

;; Function virtual void Derived2::smile() (_ZN8Derived25smileEv)
virtual void Derived2::smile() (this)
{
<bb 2>:
  return;
}

;; Function int main() (main)
int main() ()
{
  void * D.1757;
  struct Derived2 * D.1734;
  void * D.1756;
  struct Derived1 * D.1693;

<bb 2>:
  D.1756 = operator new (12);
  D.1693 = (struct Derived1 *) D.1756;
  D.1693->D.1671._vptr.Base = &_ZTV8Derived1[2];
  use (&D.1693->D.1671);
  D.1757 = operator new (12);
  D.1734 = (struct Derived2 *) D.1757;
  D.1734->D.1682._vptr.Base = &_ZTV8Derived2[2];
  use (&D.1734->D.1682);
  return 0;    
}

As we can see nicely, it's just setting one pointer - the vptr - which will point to the appropriate vtable we have seen before when creating the object. I've also dumped the assembler code for the creation of the Derived1 and call to use ($4 is first argument register, $2 is return value register, $0 is always-0-register) after demangling the names in it by the c++filt tool :)

      # 1st arg: 12byte
    add     $4, $0, 12
      # allocate 12byte
    jal     operator new(unsigned long)    
      # get ptr to first function in the vtable of Derived1
    add     $3, $0, vtable for Derived1+8  
      # store that pointer at offset 0x0 of the object (vptr)
    stw     $3, $2, 0
      # 1st arg is the address of the object
    add     $4, $0, $2
    jal     use(Base*)

What happens if we want to call bark?:

void doit(Base* b) {
    b->bark();
}

GIMPL code:

;; Function void doit(Base*) (_Z4doitP4Base)
void doit(Base*) (b)
{
<bb 2>:
  OBJ_TYPE_REF(*b->_vptr.Base;b->0) (b) [tail call];
  return;
}

OBJ_TYPE_REF is a GIMPL construct which is pretty printed into (it's documented in gcc/tree.def in the gcc SVN source-code)

OBJ_TYPE_REF(<first arg>; <second arg> -> <third arg>)

It's meaning: Use the expression *b->_vptr.Base on the object b, and store the frontend (c++) specific value 0 (it's the index into the vtable). Finally, it's passing b as the "this" argument. Would we call a function that appears at the 2nd index in the vtable (note, we don't know which vtable of which type!), the GIMPL would look like this:

OBJ_TYPE_REF(*(b->_vptr.Base + 4);b->1) (b) [tail call];

Of course, here the assembly code again (stack-frame stuff cut off):

  # load vptr into register $2 
  # (remember $4 is the address of the object, 
  #  doit's first arg)
ldw     $2, $4, 0
  # load whatever is stored there into register $2
ldw     $2, $2, 0
  # jump to that address. note that "this" is passed by $4
jalr    $2

Remember that the vptr points exactly at the first function. (Before that entry the RTTI slot were stored). So, whatever appears at that slot is called. It's also marking the call as tail-call, because it happens as the last statement in our doit function.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
4

Vtable is a per class instance, i.e., if I have 10 objects of a class which has a virtual method there is only one vtable which is shared among all the 10 objects.

All the 10 objects in this case point to same vtable.

Vinay
  • 4,743
  • 7
  • 33
  • 43
  • What about Vptr, there will be 10 vptr associated with each object or like single vtable there will be only one vptr? – Rndp13 Jun 02 '15 at 02:23
  • @Rndp13 If the vptr were also associated with the class and not the object, how on earth should a call to an overridden function be resolved at runtime? And what would be the point of having the vptr there too, as we already have all the information we need there in the vtable? – Elmar Zander Apr 05 '22 at 12:46
4

Try this at home:

#include <iostream>
struct non_virtual {}; 
struct has_virtual { virtual void nop() {} }; 
struct has_virtual_d : public has_virtual { virtual void nop() {} }; 

int main(int argc, char* argv[])
{
   std::cout << sizeof non_virtual << "\n" 
             << sizeof has_virtual << "\n" 
             << sizeof has_virtual_d << "\n";
}
dirkgently
  • 108,024
  • 16
  • 131
  • 187
  • 1
    Drawing the necessary conclusion was `left as an assignment` for the OP ;) – dirkgently Feb 18 '09 at 16:36
  • These numbers are typical, but not required though. It doesn't say how many vtables exist, or what these 4 bytes are spent on. – jalf Feb 18 '09 at 17:41
  • On a 64 bit machine, it will be 1,8,8. It can be slightly confusing as the size of empty struct is 1 byte and the other two contain a pointer each(8 bytes in case of 64 bit machine) – Anoop Mar 21 '15 at 23:37
2

A VTable is an implementation detail there is nothing in the language definition that says it exists. In fact I have read about alternative methods for implementing virtual functions.

BUT: All the common compilers (ie the ones I know about) use VTabels.
Then Yes. Any class that has a virtual method or is derived from a class (directly or indirectly) that has a virtual method will have objects with a pointer to a VTable.

All other questions you ask will depend on the compiler/hardware there is no real answer to those questions.

Martin York
  • 257,169
  • 86
  • 333
  • 562
2

To answer the question about which objects (instances from now on) have vtables and where, it's helpful to think about when you need a vtable pointer.

For any inheritance hierarchy, you need a vtable for each set of virtual functions defined by a particular class in that hierarchy. In other words, given the following:

class A { virtual void f(); int a; };
class B: public A { virtual void f(); virtual void g(); int b; };
class C: public B { virtual void f(); virtual void g(); virtual void h(); int c; };
class D: public A { virtual void f(); int d; };
class E: public B { virtual void f(); int e; };

As a result, you need five vtables: A, B, C, D, and E all need their own vtables.

Next, you need to know what vtable to use given a pointer or reference to a particular class. E.g., given a pointer to A, you need to know enough about the layout of A such that you can get a vtable that tells you where to dispatch A::f(). Given a pointer to B, you need to know enough about the layout of B to dispatch B::f() and B::g(). And so on and so on.

One possible implementation could put a vtable pointer as the first member of any class. That would mean the layout of an instance of A would be:

A's vtable;
int a;

And an instance of B would be:

A's vtable;
int a;
B's vtable;
int b;

And you could generate correct virtual dispatching code from this layout.

You can also optimize the layout by combining vtable pointers of vtables that have the same layout or if one is a subset of the other. So in the above example, you could also layout B as:

B's vtable;
int a;
int b;

Because B's vtable is a superset of A's. B's vtable has entries for A::f and B::g, and A's vtable has entries for A::f.

For completeness, this is how you would layout all the vtables we've seen so far:

A's vtable: A::f
B's vtable: A::f, B::g
C's vtable: A::f, B::g, C::h
D's vtable: A::f
E's vtable: A::f, B::g

And the actual entries would be:

A's vtable: A::f
B's vtable: B::f, B::g
C's vtable: C::f, C::g, C::h
D's vtable: D::f
E's vtable: E::f, B::g

For multiple inheritance, you do the same analysis:

class A { virtual void f(); int a; };
class B { virtual void g(); int b; };
class C: public A, public B { virtual void f(); virtual void g(); int c; };

And the resultant layouts would be:

A: 
A's vtable;
int a;

B:
B's vtable;
int b;

C:
C's A vtable;
int a;
C's B vtable;
int b;
int c;

You need a pointer to a vtable compatible with A and a pointer to a vtable compatible with B because a reference to C can be converted to a reference of A or B and you need to dispatch virtual functions to C.

From this you can see that the number of vtable pointers a particular class has is at least the number of root classes it derives from (either directly or due to a superclass). A root class is a class that has a vtable that does not inherit from a class that also has a vtable.

Virtual inheritance throws another bit of indirection into the mix, but you can use the same metric to determine the number of vtable pointers.

Validus Oculus
  • 2,756
  • 1
  • 25
  • 34
MSN
  • 53,214
  • 7
  • 75
  • 105
  • Please point out what is wrong in the answer when you down vote it. Otherwise, there is no way for us to improve content! Thanks. – Validus Oculus Apr 22 '16 at 17:40
1

All virtual classes usually have a vtable, but it is not required by the C++ standard and the storage method is dependent upon the compiler.

Judge Maygarden
  • 26,961
  • 9
  • 82
  • 99
0

Every object of polymorphic type will have a pointer to Vtable.

Where VTable stored is dependant on compiler.

yesraaj
  • 46,370
  • 69
  • 194
  • 251
0

Not necessarily

Pretty much every object that has a virtual function will have one v-table pointer. There doesn't need to be a v-table pointer for each class that has a virtual function that the object derives from.

New compilers that analyse the code sufficiently may be able to eliminate v-tables in some cases though.

For example, in a simple case: if you only have one concrete implementation of an abstract base class, the compiler knows that it can change the virtual calls to be regular function calls because whenever the virtual function is called it will always resolve to the exact same function.

Also, if there's only a couple of different concrete functions, the compiler may effectively change the call-site so that it uses an 'if' to select the right concrete function to call.

So, in cases like this the v-table isn't needed and the objects might end up not have one.

Scott Langham
  • 58,735
  • 39
  • 131
  • 204
  • Hmm. I've just been trying to find a compiler that does v-table pointer elimination. Doesn't look like there are currently any. But, the sharing of information between compilers and linkers is getting high such that they are merging together. With continued development, this may happen. – Scott Langham Feb 18 '09 at 18:03
  • This could be because actually eliminating the vptr would mean severe violation of the ABI - and this would need ensuring that any object of the class in question is never ever seen outside the module - for mere 4 bytes of memory, which may ir even may not be actually saved – jpalecek Feb 18 '09 at 19:09
  • OTOH, just not calling the methods through virtual dispatch breaks only the interface of that particular method, and the compiler can solve this by emitting another version of the code with full blown virtual dispatch. It also gives a bigger advantage, especially if the fuction can then be inlined – jpalecek Feb 18 '09 at 19:15
  • yeah look at my example below. omitting the v-table pointer will cause some hard headaches to be solved. however, omitting vtables might be easy, tho then the RTTI entry would be omitted - gcc uses the vtable to reference to the RTTI data. – Johannes Schaub - litb Feb 18 '09 at 19:45