In C++, as I know, memory layout of an object with two derived classes will be like this:
|---------|
| base 1 |
|---------|
| base 2 |
|---------|
| derived |
|---------|
If a function accepts a pointer to base 2
, then object pointer will be sliced. Inside that function, if I call a virtual function of base 2
, overrided in derived
, which uses data in base 1
, then how compiler manages to properly handle this?
Eg:
#include<stdio.h>
class A {
public:
int a = 10;
virtual void ff() {
}
};
class B {
public:
virtual void f() {
printf("%c\n", 'B');
}
};
class C : public A, public B {
public:
virtual void f() override {
printf("In C::f %p\n", this);
printf("%c %d\n", 'C', a);
}
};
void func(B* b) {
printf("In func %p\n", b);
b->f();
}
int main() {
C c;
printf("In main %p\n", &c);
func(&c);
}
Output:
In main 0x7ffc70c644a0
In func 0x7ffc70c644b0
In C::f 0x7ffc70c644a0
C 10
Here is compiler explorer link for that. If you run this, address in func()
is offset by the sizeof(A)
. But when it calls b->f()
, the address is corrected properly. The generated code contains non-virtual thunk to C::f():
which does this. But I'm unable to find when that code is called. vtable contains refernce to both C::f()
and non-virtual thunk to C::f():
. But in runtime, how it finds proper variant?