How does the compiler generate code for virtual function calls?
c++
Solution
What your picture is missing is an arrow from a `CAT` and a `SmallCAT` objects to their corresponding vtbls. The compiler embeds a pointer to vtbl into the object itself - one can think of it as a hidden member variable. That is why it is said that adding the first virtual function "costs" you one pointer per object in memory footprint. The pointer to vtbl is set up by the code in the constructor, so all the compiler-generated virtual call needs to do in order to get to its vtable at runtime is dereferencing the pointer to `this`.
Of course this gets more complicated with virtual and multiple inheritance: the compiler needs to generate a slightly different code, but the basic process remains the same.
Here is your example explained in more details:
CAT *p1,*p2;
p1 = new SmallCat; //suppose its vtbl address is 0x1234;
// The layout of SmallCat object includes a vptr as a hidden member.
// At this point, the value of this vptr is set to 0x1234.
p2 = new CAT; //suppose its vtbl address is 0x5678;
// The layout of Cat object also includes a vptr as a hidden member.
// At this point, the value of this vptr is set to 0x5678.
(*p1->vptr[i])(p); //should use vtbl at 0x1234
// Compiler has enough information to do that, because it squirreled away 0x1234
// inside the SmallCat object at the time it was constructed.
(*p2->vptr[i])(p); //should use vtbl at 0x5678
// Same deal - the constructor saved 0x5678 inside the Cat, so we're good.
Problem
``` CAT *p; ... p->speak(); ... ``` Some book said that the compiler will translate p->speak() to: ``` (*p->vptr[i])(p); //i is the idx of speak in the vtbl ``` My question is: since at compile time, it is impossible to know the real type of p, which means it is impossible to know which vptr or vtbl to be use. So, how does the compiler generate correct code? [modified] For example: ``` void foo(CAT* c) { c->speak(); //if c point to SmallCat // should translate to (*c->vptr[i])(p); //use vtbl at 0x1234 //if c point to CAT // should translate to (*c->vptr[i])(p); //use vtbl at 0x5678 //since ps,pc all are CAT*, why does compiler can generate different code for them //in compiler time? } ... CAT *ps,*pc; ps = new SmallCat; //suppose SmallCat's vtbl address is 0x1234; pc = new CAT; //suppose CAT's vtbl address is 0x5678; ... foo(ps); foo(pc) ... ``` Any ideas? Thanks.