Inside void bar(A * a)
, the pointer is definitely to an A
object. That A
object may be a subobject of something else like a B
, but that's irrelevant. The A
is self-contained and has its own vtable pointer which links to foo
.
When the conversion from B *
to A *
occurs, such as when bar
is called with a B *
, a constant offset may be added to the B *
to make it point to the A
subobject. If the first thing in every object is the vtable, then this will also set the pointer to the A
vtable as well. For single inheritance, the adjustment is unnecessary.
Here is what memory looks like for a typical implementation:
| ptr to B vt | members of C | members of B | ptr to AB vt | members of A |
B vt: | ptrs to methods of C (with B overrides) | ptrs to methods of B |
AB vt: | ptrs to methods of A (with B overrides) |
(Note that typically the AB vt
is really still part of the B vt
; they would be contiguous in memory. And ptrs to methods of B
could then go after ptrs to methods of A
. I just wrote it this way for formatting clarity.)
When you convert a B *
to an A *
, you go from this:
| ptr to B vt | members of C | members of B | ptr to AB vt | members of A |
^ your B * pointer value
to this:
| ptr to B vt | members of C | members of B | ptr to AB vt | members of A |
^ your A * pointer value
Using a static_cast
from A *
to B *
will move the pointer backwards, in the other direction.