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?
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?
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.
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.
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.
Every object of polymorphic type will have a pointer to Vtable.
Where VTable stored is dependant on compiler.
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.
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.
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";
}
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.
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.
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.