I have a confusion regarding vtable after reading more about name mangling. for ex:
class Base
{
public:
virtual void print()
{
}
};
class A : public Base
{
public:
void hello()
{
....
}
void print()
{
}
};
A obj;
obj.hello();
Base* test = new A();
test->print();
As per my understanding after the name manging obj.hello()
call will be converted to something like _ZASDhellov(&obj)
now
test->__vtable[_ZASDprintv](&test(dynamic cast to derived???))
is correct?Firstly, vtables are not in any way part of the C++ language, but rather an implementation detail used by particular compilers. Below I describe one way it is commonly used as such.
Second, your function hello
is not virtual. To make it virtual, you would simply pre-pend virtual
to the declaration.
Assuming it is now virtual: Your guess is quite close. In fact, the vtable
(to which a pointer is stored with every instance of a virtual class) is an array of function pointers. The way that a particular function is looked up in it is by its ordinal. The first declared virtual function in A
is the first entry in its vtable
, the second one is the second entry and so on. If A
had a base class, the index of A
's first (non-override) virtual function in the table would be n+1
, where n
is the index of the last virtual function of its base class. If A
has more than one base class, their entries precede A
's entries in order of their declaration as base classes of A
.
If A
uses virtual inheritance, the picture is a bit more complicated than that, I won't elaborate unless you're specifically interested.
UPDATE: I'll add a very brief description for the virtual inheritance case as requested. If A
had Base
as a virtual base class, A
's vtable
would store at the very beginning (before the function addresses) the byte offset of where Base
's data starts within the A
object. This is necessary because, unlike in normal inheritance, a base class does not have its data precede the derived class's data - instead it follows it. So in effect, any function call to a virtual function defined in Base
has to have its this
pointer offset by that amount. Additionally, Base
would have to have its own vtable
pointer, right at the beginning of its data where it expects to find it. Thus the full A
object would contain two vtable
pointers instead of one. The actual vtable
pointed to by this second pointer would be the same one as the first vtable
pointer, except advanced to skip the offset entry described above (so that any Base
code using the vtable
would find the first virtual function at the beginning where it is expected). Apart from these differences, the vtable
itself is the same as before.