4

When I build, demangle and clean this short program:

struct Base {
    virtual int compute() { return 42; }
};

struct Derived: public Base {
    int compute() override { return 23; }
};

int main() {
    Base* a = new Derived;
    a->compute();
}

Which I do with some home made magic:

g++ -g -o- -S foo.cpp | \
    c++filt | \
    perl -pe 's/^\.LA\w+:\r?\n//gm' | \
    perl -0777 -pe 's/^\.Ldebug\w+:\r?\n(\s+\..+?\r?\n)+//gm' | \
    perl -pe 's/^\.L\w+:\r?\n//gm' | \
    perl -pe 's/^\s+\.(align|section|weak|loc|file|cfi).+\r?\n//gm' | \
    highlight --out-format=ansi --syntax=asm

I get this:

vtable for Derived:
        .quad   0
        .quad   typeinfo for Derived
        .quad   Derived::compute()
        .type   vtable for Base, @object
        .size   vtable for Base, 24
vtable for Base:
        .quad   0
        .quad   typeinfo for Base
        .quad   Base::compute()
        .type   typeinfo for Derived, @object
        .size   typeinfo for Derived, 24

I notice that my vtable has the following structure:

0. ???
1. Pointer to typeinfo
2. Pointer to first virtual method
3. Pointer to second virtual method
4. ...

I did not understood what the 0 at vtable[0] was, but after discovering this other SO question, I have written another example to understand this offset to top thing.

https://godbolt.org/z/eWScPK

This one uses virtual inheritance.

struct Top {
    virtual void foo() { }
};

struct Left: public Top { // note: non virtual
    void foo() override { }
};

struct Right: virtual public Top {
    void foo() override { }
};
// note: Bottom is not a "diamond", Top is base twice
struct Bottom: public Left, public Right {
    void foo() override { }
};

int main() {
    Bottom bottom;
    bottom.foo();
}

This time my vtable looks like this:

vtable for Bottom:
        .word   4
        .word   0
        .word   typeinfo for Bottom
        .word   Bottom::foo()
        .word   0
        .word   -4
        .word   -4
        .word   typeinfo for Bottom
        .word   non-virtual thunk to Bottom::foo()

So I am able to explain the first 0 that became a 4, but I am still not able to explain the new structure of my vtable.

I am looking for a more detailed answer that would explain this latter example.

curiousguy
  • 8,038
  • 2
  • 40
  • 58
nowox
  • 25,978
  • 39
  • 143
  • 293
  • 3
    Try it with virtual inheritance. Does the 0 change? – StoryTeller - Unslander Monica Apr 25 '19 at 08:50
  • virtual inheritance means one or more virtual base classes. If that still doesn't mean anything then a quick search for "virtual base classes" should be enlightening. – StoryTeller - Unslander Monica Apr 25 '19 at 08:57
  • @StoryTeller Yes it does change with https://godbolt.org/z/eWScPK, but it generates other questions because another 0 follows. I'll edit my question – nowox Apr 25 '19 at 12:52
  • Each base object needs to know the distance from most derived object from that base. Also the position of each virtual base. Note that primary bases share their vptr and virtual bases can be primary or not depending on complete layout. `Top` is primary in `Left` which is primary in `Bottom`; `Top` is primary in complete `Right` also in `Right` base of `Bottom` (I think); so using `Left` will be most efficient than `Right` (slightly). [Corrected comment after I noticed no virtual inheritance in `Left`!] – curiousguy Apr 29 '19 at 01:32

0 Answers0