I came across articles where in they explain about vptr and vtable. I know that the first pointer in an object in case of a class with virtual functions stored, is a vptr to vtable and vtable's array entries are pointers to the function in the same sequence as they occur in class ( which I have verified with my test program). But I am trying to understand what syntax must compiler put in order to call the appropriate function.
Example:
class Base
{
virtual void func1()
{
cout << "Called me" << endl;
}
};
int main()
{
Base obj;
Base *ptr;
ptr=&obj;
// void* is not needed. func1 can be accessed directly with obj or ptr using vptr/vtable
void* ptrVoid=ptr;
// I can call the first virtual function in the following way:
void (*firstfunc)()=(void (*)(void))(*(int*)*(int*)ptrVoid);
firstfunc();
}
Questions:
1. But what I am really trying to understand is how compiler replaces the call to ptr->func1()
with vptr
?
If I were to simulate the call then what should I do? should I overload the ->
operator. But even that would not help as I would not know what really the name func1
is. Even if they say that compiler accesses the vtable through vptr, still how does it know that the entry of func1
is the first array adn entry of func2
is the second element in the array? There must be some mapping for the names of function to the elements of array.
2. How can I simulate it. Can you provide the actual syntax that compiler uses to call function func1
(how does it replace ptr->func1()
)?
Don't think of a vtable as an array. It's only an array if you strip it of everything C++ knows about it other than the size of its members. Instead, think of it as a second struct
whose members are all pointers to functions.
Suppose I have a class like this:
struct Foo {
virtual void bar();
virtual int baz(int qux);
int quz;
}
int callSomeFun(Foo* foo) {
foo->bar();
return foo->baz(2);
}
Breaking it down 1 step:
class Foo;
// adding Foo* parameter to simulate the this pointer, which
// in the above would be a pointer to foo.
struct FooVtable {
void (*bar)(Foo* foo);
int (*baz)(Foo* foo, int qux);
}
struct Foo {
FooVtable* vptr;
int quz;
}
int callSomeFun(Foo* foo) {
foo->vptr->bar(foo);
return foo->vptr->baz(foo, 2);
}
I hope that's what you're looking for.