Search code examples
c++inheritancemultiple-inheritancevirtual-functionsmemory-layout

Static cast to base class gives unexpected results when base has a virtual function


struct Base1{

    int b1[100];

};

struct Base2{

    int b2;

    virtual void foo() {}

};

struct Derived : public Base1, public Base2{

    int d;

};

int main(){

    Derived D;
    Base2* p_B2 = &D;

    std::cout << &D << "\n";
    std::cout << p_B2 << "\n";

    std::cout << sizeof( D) << "\n";
    std::cout << sizeof( *p_B2) << "\n";

    std::cout << &(D.b2) << "\n";
    std::cout << &(p_B2->b2) << "\n";

    return 0;

}

If the virtual function is commented out, the output is something like:

0x7fffffffdcb0
0x7fffffffde40
408
4
0x7fffffffde40
0x7fffffffde40

If the virtual function is there, the output is:

0x7fffffffdca0
0x7fffffffdca0
416
16
0x7fffffffdca8
0x7fffffffdca8

The size difference is the v-pointer + padding, but where is the offset? Why do those point to the same address? Why is there only 8 bytes (the v-pointer I assume) difference between D and D.b2 when there should be at least 100 int-s between them?

(Also my debugger (gdb) shows p_B2 as "Derived" type.)


Solution

  • The compiler is free to lay out your classes however it likes, presumably your compiler always puts virtual classes at the beginning and any non-virtual classes after that.

    You can't rely on any particular ordering of classes.