Reputation: 109
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
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>+56
refers to.
Upvotes: 0
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