0

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?

Sourav Kannantha B
  • 2,860
  • 1
  • 11
  • 35
  • It just looks up the function address in the vtable. Note there is no slicing here – Alan Birtles Feb 15 '22 at 10:46
  • pointers don't slice. Objects do. Does this answer your question? https://stackoverflow.com/questions/274626/what-is-object-slicing. (it doesnt but it should help to clarify part of your confusion) – 463035818_is_not_an_ai Feb 15 '22 at 10:46
  • @AlanBirtles In vtable, it looks up the address of `C::f()` and it gets it. But it can't directly call that with the pointer it is having (if you see the output, the address is off by 16 bytes). It has to readjust the pointer and then call `C::f()`. But, this readjust can't be added at the beginning of `C::f()` since sometimes it may get valid pointer, and there is no need to readjust. This readjust also can't be added in `func()` just before calling f, since target f depends on actual type of b, which can change. – Sourav Kannantha B Feb 15 '22 at 11:10
  • I don't think you need to worry about the details of how the v-table is implemented (it will vary between compilers too), it will contain whatever information is required by the runtime to call your function – Alan Birtles Feb 15 '22 at 11:15
  • @AlanBirtles I actually wanted to know atleast how one such is implemented. I am trying to build compiler :) – Sourav Kannantha B Feb 15 '22 at 11:17
  • @AlanBirtles If you can, explain the vtable in linked compiler output. I tried, but couldn't. – Sourav Kannantha B Feb 15 '22 at 11:19

0 Answers0