刘芮杉
刘芮杉

Reputation: 109

what does "<vtable for A+16>" mean?

This is my code. I just want to have a look at the memory layout of virtual inherit.

#include<iostream>
using namespace std;

class A{
    private:
        int a;
    public:
        virtual void print() const{
            cout << a << endl;
        }

};

class B:public virtual A{
    private:
        int b;
    public:
        void print() const{
            cout << b << endl;
        }
};



int main(){
    A a;
    B b;
    return 0;
}

Then in gdb, I used

p a
p b

The output is

(gdb) p a
$1 = {
  _vptr.A = 0x400b40 <vtable for A+16>, 
  a = 0
}
(gdb) p b
$2 = {
  <A> = {
    _vptr.A = 0x400b18 <vtable for B+56>, 
    a = 4196384
  }, 
  members of B: 
  _vptr.B = 0x400af8 <vtable for B+24>, 
  b = 0
}
(gdb) 

I know the meaning of _vptr.A and _vptr.B but I don't understand the what does vtable for B+24 or A+16 mean.

Thanks for the answer!

Upvotes: 8

Views: 1368

Answers (2)

Izana
Izana

Reputation: 3135

referenced from this post:

IMO, first thing first, in B, you are doing implicit shadowing without virtual keyword, which is a bad practice and it will give you surprises at runtime from different compilers.

Based on 64-bits arch.

<vtable for A+16> means offset A's vtable address by 16, which is the first function entry. Follow the assembly code of that post applying your code:

vtable for A:
        .quad   0
        .quad   typeinfo for A
        .quad   A::print() const

a quad is 4 words, which means 8. Therefore, the address for A::print() is address (label) vtable for A plus 16 offsets, which is in the text section.

Same for B, which is more complicated because you are using pure virtual inheritance.

vtable for B:
        .quad   16
        .quad   0
        .quad   typeinfo for B
        .quad   B::print() const
        .quad   -16
        .quad   -16
        .quad   typeinfo for B
        .quad   virtual thunk to B::print() const

In general, there's only one vtable for B, as it is shown above. But you can view it as 2 vtables conceptually concatenated.

For B part of B vtable

vtable for B:
        .quad   16
        .quad   0
        .quad   typeinfo for B
        .quad   B::print() const

For A part of B vtable:

        .quad   -16
        .quad   -16
        .quad   typeinfo for B
        .quad   virtual thunk to B::print() const

That's what <vtable for B>+56refers to.

Upvotes: 0

Gene
Gene

Reputation: 47010

The listing for a says that it's a class with two fields: a vptr that points to a byte with offset 16 inside the vtable for A and a data element a containing zero.

The second is along the same lines but more complicated due to the virtual base class. It's saying b consists of 3 fields: an instance of A with fields similar to those above, and then the two elements of B, again as above. This time the vptr is directed at offset 24.

Why does the vptr point into the middle of the table rather than its start? You'd have to know more about the details of gcc memory layout to say, and I don't. It's possible the initial bytes are RTTI (run time type information) and the given offset is the first element of the array of virtual function pointers. There are uncountably many other options.

NB. There is some good information in this earlier article saying there are always 2 pointers leading the vtable: one for the multiple inheritance top pointer and another for RTTI. If your machine and compiler are 64 bits (you really should mention this; it's important), this coincides with 16 bytes of pointers. B could be 24 bytes because there's an extra pointer to access the virtual base class.

Upvotes: 8

Related Questions