在书中提到了#34;内部的C ++对象模型"派生类具有n - 1
个额外虚拟表,n
是基类的数量。我用g ++编译器进行了一些实验,我的机器是64位。
以下是我的代码。
class A{
private:
int a;
public:
virtual void print() const{
cout << a << endl;
}
};
class B : A{
private:
int b;
public:
virtual void set(int num){
b = num;
}
};
class C : public A, public B{
private:
int c;
public:
void print() const{
cout << c << endl;
}
void set(int num){
c = num;
}
};
我在gdb中检查每个类的内存布局:
(gdb) p a
$1 = (A) {
_vptr.A = 0x400bb0 <vtable for A+16>,
a = 0
}
(gdb) p b
$2 = (B) {
_vptr.B = 0x400b90 <vtable for B+16>,
b = 4196384
}
(gdb) p c
$3 = (C) {
<A> = {
_vptr.A = 0x400b50 <vtable for C+16>,
a = 4197101
},
<B> = {
_vptr.B = 0x400b70 <vtable for C+48>,
b = 0
},
members of C:
c = 0
}
它表明C类中有两个vptrs
。然后我用-fdump-class-hierarchy
编译它获得了一些信息。
Vtable for A
A::_ZTV1A: 3u entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI1A)
16 (int (*)(...))A::print
Class A
size=16 align=8
base size=12 base align=8
A (0x0x7fe4654956c0) 0
vptr=((& A::_ZTV1A) + 16u)
Vtable for B
B::_ZTV1B: 3u entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI1B)
16 (int (*)(...))B::set
Class B
size=16 align=8
base size=12 base align=8
B (0x0x7fe465495720) 0
vptr=((& B::_ZTV1B) + 16u)
Vtable for C
C::_ZTV1C: 7u entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI1C)
16 (int (*)(...))C::print
24 (int (*)(...))C::set
32 (int (*)(...))-16
40 (int (*)(...))(& _ZTI1C)
48 (int (*)(...))C::_ZThn16_N1C3setEi
Class C
size=32 align=8
base size=32 base align=8
C (0x0x7fe46516e690) 0
vptr=((& C::_ZTV1C) + 16u)
A (0x0x7fe465495780) 0
primary-for C (0x0x7fe46516e690)
B (0x0x7fe4654957e0) 16
vptr=((& C::_ZTV1C) + 48u)
然后我对以下问题感到困惑。
Class A
size=16 align=8
base size=12 base align=8
我不明白为什么A类的大小是16,基本大小和对齐是什么意思?我认为A类的大小应为12字节,vptr
为8字节,int a
为4字节。 B级也是如此。vtables
但结果显示只有一个有7个条目。这个vtable
和C级的两个vptr
之间的关系是什么?vptr=((& C::_ZTV1C) + 48u)
,48是什么意思?并且C类vtable
的最后一个条目表明了这一点
48 (int (*)(...))C::_ZThn16_N1C3setEi
这是什么意思?它不是虚函数的名称和顶部的偏移量。为什么第二个vptr
指向此条目?答案 0 :(得分:0)
与vtables有关。对于多重继承,一个对象可能有几个(对于每个包含虚拟成员函数的超类,可能只有一个)。
将一个对象指针转换为某些父类可能需要添加一些偏移量(以获得正确的vtable和成员函数)。