I'm reading multiple inheritance for c++ An Example in the paper:(page 377)
class A {virtual void f();};
class B {virtual void f(); virtual void g();};
class C: A, B {void f();};
A* pa = new C;
B* pb = new C;
C* pc = new C;
pa->f();
pb->f();
pc->f();
pc->g()
(1) Bjarne wrote: On entry to C::f
, the this
pointer must point to the beginning of the C
object (and not to the B
part). However, it is not in general known at compile time that the B
pointed to by pb
is part of a C
so the compiler cannot subtract the constant delta(B)
. So we have to store the delta(B) for the runtime which is actually stored with the vtbl. So the vtbl entry now looks like:
struct vtbl_entry {
void (*fct)();
int delta;
}
An object of class c will look like this:
---------- vtbl:
vptr -------------->-----------------------
A part C::f | 0
---------- -----------------------
vptr -------------->-----------------------
B part C::f | -delta(B)
---------- B::g | 0
C part -----------------------
----------
Bjarne wrote:
pb->f() // call of C::f:
register vtbl_entry* vt = &pb->vtbl[index(f)];
(*vt->fct)((B*)((char*)pb+vt->delta)) //vt->delta is a negative number I guess
I'm totally confused here. Why (B*) not a (C*) in (*vt->fct)((B*)((char*)pb+vt->delta))
???? Based on my understanding and Bjarne's introduction at the first sentence at 5.1 section at 377 page, we should pass a C* as this
here!!!!!!
Followed by the above code snippet, Bjarne continued writing: Note that the object pointer may have to be adjusted to po int to the correct sub-object before looking for the member pointing to the vtbl.
Oh, Man!!! I totally have no idea of what Bjarne tried to say? Can you help me explain it?
It is a
C*
, it's just not typed as such.Frankly, that's a pretty terrible explanation and not really how it's done. It's a lot better and easier to store function pointers in the vtable.
When the compiler generates the thunks, it knows the derived object they're thunking to, so they don't need to store the offset in the vtable. The compiler can simply offset the pointer inside the thunk and then delegate to the appropriate method with the pointer. Of course, this thunk is pretty much generated assembly only without any C++ representation, so it would be invalid to state that that the pointers within have any particular C++ type.