views:

1442

answers:

10

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?

A: 

Edit: Some people sure like their downvotes. It might be informative if they also dropped a comment saying why. As it is, I don't know if I got -4 because 1) everyone knew the correct answer, and simply misunderstood mine, 2) They saw Scott's comment and blindly assumed that my answer must be wrong then, or 3) I misunderstood the question.

So here's my heavily revised version, now featuring a full example of how the compiler may implementation of a vtable: (Not the 'may'. The language spec doesn't say how this should be implemented, so it is up to the individual compiler. But the following is a typical solution)

A derived class contains a full copy of its base class. Which means that it also contains the vtable of the base class. Overwriting entries in this is how virtual function overriding works.

An example:

class Base {
 virtual void Foo();
 int x;
};

will typically contain a vtable with one entry in addition to the rest of the class contents. That is, the class will look like this in memory:

Base begin
  Vtable entry for Foo()
  x
Base end

Anyone calling Foo knows that they need to follow the pointer defined at offset 0 from Base's vtable.

Now let's say we have a class Derived:

class Derived : Base {
 void Foo();
 int x
};

This class does not define a completely new function, it overrides the Foo() defined in Base. That means it does not need a vtable for itself, since it doesn't define any new virtual methods. It'll look something like this then:

Derived Begin
  Base begin
    Vtable entry for Foo()
    x
  Base end
  y
Derived End

When class Derived is instantiated, it takes the address of the function Derived::Foo(), and writes it into the vtable entry of Base.

So if I call it like this:

Derived* d = new Derived(); #1
d->Foo() // #2
Base* b = d;
b->Foo() // #3

the following happens: in #1, we create a Derived object. During its initialization, it creates the inner Base object, including its vtable. It then writes the pointer &Derived::Foo into the vtable entry of that Base instance.

In #2, everything is straightforward. We call Foo() on the derived objeect. Since this is a virtual function defined in Base, the compiler looks at the appropriate offset (0) from the Base instance, and follows the pointer found there, which we set to point to Derived::Foo() in #1. Thus the correct function gets called.

In #3, the compiler treats our Derived instance as a Base. That means it only looks at the Base instance located at the start of the Derived object according to my sample memory layout.

So the compiler once again looks at Base's vtable (because this is the only vtable it knows of. It doesn't know that the object is actually a Derived, and that it may or may not have its own vtable for any functions it defines)

And oh my, isn't it lucky that we in #1 chose to write &Derived::Foo into Base's vtable rather than Derived's? Because that is what makes it possible for #3 to call Derived::Foo() as we'd expect. It follows the pointer stored in Base's vtable, which no longer points to Base::Foo, but has been overwritten to point to Derived::Foo.

As the above shows, the derived class must modify the base class's vtable in order for our polymorphism to work properly. Having its own vtable to modify simply does not solve the problem. Line #3 above will call Base::Foo(), which is wrong.

jalf
An object only has a reference to the v-table for its class. That v-table may contain entries that point to methods of the base class if those methods were not overridden by this class.
Scott Langham
No, the vtable for the base class which defines a virtual function foo contains an entry for foo. Any derived class which overrides foo simply places a different pointer in the foo entry of the vtable in the base class. And anyone calling the foo function follows the pointer in the base class vtable
jalf
You have an abstract class Animal with a virtual function MakeSound. You have two concrete classes Dog and Cow that derive from animal. Both implement MakeSound. According to your last comment, both Dog and Cow will put their virtual function in the v-table of Animal.
Scott Langham
There is only 1 slot in the v-table for the MakeSound function. How can both Dog and Cow put their function in that one slot. They can't, that's why Dog and Cow have their own v-table and do not share Animal's v-table.
Scott Langham
well, Animal's vtable stays the same, whether or not it has no or a million derived classes. what changes is the vtable-pointer, which, when you create a Cow object, will point to Cow's vtable. that vtable is essentially animal's vtable copied with some pointers maybe changed.
Johannes Schaub - litb
at least that is what i think happens. never implemented a compiler that does it though :)
Johannes Schaub - litb
v-tables all get generated at compile time. 1 per class. They do not get created at run-time as I think possibly you are describing. Also, v-tables are not called based on the type you're pointing at it with. If you have a Base* base; base->Method() . The despatch for Method will be done via the
Scott Langham
vtable for whatever exact type base is (worked out by looking at it's vtable (stored as a known position within the object)). It does not look in the v-table for Base, just because you've got a Base*. The type of what you're currently referencing the object with is irrelevant.
Scott Langham
You don't need to modify any vtables. Derived points to a vtable that has entries that are copied from Base. The vtable itself is immutable.
MSN
+1  A: 

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
+2  A: 

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
A: 

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

Where VTable stored is dependant on compiler.

yesraaj
+6  A: 

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
A: 

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
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
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
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
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
+4  A: 

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
Answers for VS2005: 1, 4, 4
Joe Schneider
Drawing the necessary conclusion was `left as an assignment` for the OP ;)
dirkgently
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
A: 

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
+3  A: 

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
A: 

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; };

You need four 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.

MSN