0

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?

2
  • Isn't this essentially a duplicate of your previous (unanswered) question? Commented Jun 10, 2015 at 22:51
  • 2
    "... of what Bjarne tried ..." Cool, you're that kinda familiar with him ;-) ... Commented Jun 10, 2015 at 22:53

3 Answers 3

2

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.

struct vtbl {
    void(*f)(B* b);
};
struct B {
   vtbl* vtable;
};
// Invoke function:
B* p = init();
p->vtable->f(p);
// Function pointer points to:
void f_thunk(B* b) {
    C* c = (char*)b - delta(B);
    C::f(c);
}

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.

Sign up to request clarification or add additional context in comments.

3 Comments

@FihopZz: The compiler doesn't generate a thunk unless it needs to. But it must generate a new thunk every time it either calls a different function or needs to have a different offset.
For A* p = new C(); p->f(), please verify me. p->vtable->f(p), (A's vtable and function pointer) since A pointer starts from the same address as C pointer, p actually points to the start address of the C object. So p->vtable->f(p) already finished the job. There is no need to generate a thunk?
Not in that case, no. But there are plenty of cases where A and C do not start from the same address.
1

You're getting lost in the weeds here.

Are you trying to write your own C++ compiler? If so, feel free to ignore me. But if you're just trying to understand and learn C++ virtual inheritance, which is what it sounds like, none of what you wrote matters much.

Only compiler writers need to fully understand and figure out how the vtbl works, in all the gory details, in order to actually implement C++. It is not needed to effectively program and develop in C++. All that needs to be understood is how virtual inheritance works, from purely the class's viewpoint. As long as you understand that when invoking pb's method you're actually ending up invoking C's method, and why (with the why being simply "because it is actually an instance of C), that's pretty much all that needs to be understood.

Oh, and your class should probably have a virtual destructor, but that's a different story.

The vtbl is typically not even accessible by C++ code. And the C++ standard does not even require a C++ compiler to actually implement anything that's called "vtable". The only requirement is a specification for how virtual inheritance, and virtual method calls must work. Any actual implementation that produces the same results is compliant.

3 Comments

There's no reason why a person should not attempt to understand the most common implementation techniques.
@Puppy Except keeping whats left of your sanity, that is a pretty good reason. :)
I agree, It's worth a historical note that the first C++ compilers compiled to C source (which was then itself compiled). I thoroughly enjoy Stroustrup's writing but he has a tendency to explain things from the point of view of someone inside looking out not outside looking in. He sometimes explains how things work by how he implemented them and assumes you're a totally fluent C programmer before you even start. Ironic that such an evangelist of abstraction and data hiding shows a habit of giving concrete implementations and exposing data!
0

I'm totally confused here. Why (B*) not a (C*) in (*vt->fct)

At that level, the only known type is B. The actual object could be of type C, Foo, or Bar.

However, that paper is a bit dated. Actual implementations in modern compiler could be very different. @Puppy's answer shows how it can be done without adding delta(B) to the vtable.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.