GDB查看C++对象布局
C++类包含数据成员(static,nonstatic)和成员函数(static、nonstatic、virtual)。
C++对象模型完成对数据成员和成员函数的构建。本文对以下模型的构建进行分析:
单一类
单继承无重写
单继承有重写
多继承
虚继承
菱形继承
单一类
class Base{
public:
Base():m_base(0){}
virtual ~Base(){}
virtual void print() const { cout<<"Base print()"<<endl; }
static int GetStaticVal();
protected:
int m_base;
static int m_tmp;
};
GDB查看对象如下:
(gdb) set print object on
(gdb) set print vtbl on
(gdb) set print pretty on
((gdb) p base
$7 = (Base) {
_vptr.Base = 0x403a50 <vtable for Base+16>,
m_base = 0,
static m_tmp = 1
}
(gdb) info vtbl base
vtable for ‘Base’ @ 0x403a50 (subobject @ 0x7fffffffdf60):
[0]: 0x402830 Base::~Base()
[1]: 0x402930 Base::~Base()
[2]: 0x402ae0 <Base::print() const>
结论:
对象由vptr和成员数据构成。
为什么会有两个虚析构函数?
gcc里虚析构函数在虚表里是一对;一个叫complete object destructor, 另一个叫deleting destructor,区别在于前者只执行析构函数不执行delete(),后面的在析构之后执行deleting操作。应该是gcc想把non-detele的析构函数轮一遍后,然后用delete析构直接就清理掉整个内存。
单继承无重写
class DerivedSimple : public Base{
public:
DerivedSimple(){}
virtual ~DerivedSimple(){}
virtual void DerivedSimplePrint() { cout<<"DerivedSimplePrint()"<<endl; }
private:
int m_derivedSimple;
};
GDB查看对象如下:
(gdb) p ds
$10 = (DerivedSimple) {
Base> = {
_vptr.Base = 0x403a90 <vtable for DerivedSimple+16>,
m_base = 0,
static m_tmp = 1
},
members of DerivedSimple:
m_derivedSimple = 0
}
(gdb) info vtbl ds
vtable for ‘DerivedSimple’ @ 0x403a90 (subobject @ 0x7fffffffdf70):
[0]: 0x402840 DerivedSimple::~DerivedSimple()
[1]: 0x402940 DerivedSimple::~DerivedSimple()
[2]: 0x402ae0 <Base::print() const>
[3]: 0x402a70 DerivedSimple::DerivedSimplePrint()
结论:
对象由基类的vptr、成员数据和派生类成员数据顺序构成。
派生类的虚函数放入到基类的虚函数表。
单继承有重写
class DerivedRewrite : public Base{
public:
DerivedRewrite(){}
virtual ~DerivedRewrite(){}
virtual void DerivedRewritePrint() { cout<<"DerivedRewritePrint()"<<endl; }
virtual void print() const { cout<<"DerivedRewrite print()"<<endl; };
private:
int m_derivedRewrite;
};
GDB查看对象如下:
(gdb) p dr
$11 = (DerivedRewrite) {
Base> = {
_vptr.Base = 0x403ad0 <vtable for DerivedRewrite+16>,
m_base = 0,
static m_tmp = 1
},
members of DerivedRewrite:
m_derivedRewrite = 0
}
(gdb) info vtbl dr
vtable for ‘DerivedRewrite’ @ 0x403ad0 (subobject @ 0x7fffffffdf80):
[0]: 0x402850 DerivedRewrite::~DerivedRewrite()
[1]: 0x402950 DerivedRewrite::~DerivedRewrite()
[2]: 0x402d90 <DerivedRewrite::print() const>
[3]: 0x402d20 DerivedRewrite::DerivedRewritePrint()
结论:
对象由基类的vptr、成员数据和派生类成员数据顺序构成。
与无重写不同,派生类的重写的虚函数覆盖基类的虚函数表的同名函数。
多继承
class BaseMult{
public:
BaseMult(){}
virtual ~BaseMult(){}
virtual void print() const { cout<<"BaseMult print()"<<endl; }
protected:
int m_baseMult;
};
class DerivedMult : public Base,public BaseMult{
public:
DerivedMult(){}
virtual ~DerivedMult(){}
virtual void DerivedMultPrint() { cout<<"DerivedMultPrint()"<<endl; }
private:
int derivedMult;
};
GDB查看对象如下:
(gdb) p dm
$12 = (DerivedMult) {
Base> = {
_vptr.Base = 0x403b50 <vtable for DerivedMult+16>,
m_base = 0,
static m_tmp = 1
},
BaseMult> = {
_vptr.BaseMult = 0x403b80 <vtable for DerivedMult+64>,
m_baseMult = 0
},
members of DerivedMult:
m_derivedMult = 0
}
(gdb) info vtbl dm
vtable for ‘DerivedMult’ @ 0x403b50 (subobject @ 0x7fffffffdf90):
[0]: 0x402870 DerivedMult::~DerivedMult()
[1]: 0x402970 DerivedMult::~DerivedMult()
[2]: 0x402ae0 <Base::print() const>
[3]: 0x402e70 DerivedMult::DerivedMultPrint()
vtable for ‘BaseMult’ @ 0x403b80 (subobject @ 0x7fffffffdfa0):
[0]: 0x402880 <non-virtual thunk to DerivedMult::~DerivedMult()>
[1]: 0x402990 <non-virtual thunk to DerivedMult::~DerivedMult()>
[2]: 0x402e00 <BaseMult::print() const>
结论:
对象由第一个基类的vptr、成员数据,第二个基类的vptr、成员数据和派生类成员数据顺序构成。
基类拥有各自的虚函数表,派生类的虚函数放入到第一个基类的虚函数表。
虚继承
class DerivedVirtual : virtual public Base{
public:
DerivedVirtual(){}
virtual ~DerivedVirtual(){}
virtual void DerivedVirtualPrint() { cout<<"DerivedVirtualPrint()"<<endl; }
virtual void print() const { cout<<"DerivedVirtual print()"<<endl; };
private:
int m_derivedVirtual;
};
GDB查看对象如下:
(gdb) p dv
$13 = (DerivedVirtual) {
Base> = {
_vptr.Base = 0x403c18 <vtable for DerivedVirtual+88>,
m_base = 0,
static m_tmp = 1
},
members of DerivedVirtual: (派生类在先)
_vptr.DerivedVirtual = 0x403bd8 <vtable for DerivedVirtual+24>,
m_derivedVirtual = 0
}
(gdb) info vtbl dv
vtable for ‘DerivedVirtual’ @ 0x403bd8 (subobject @ 0x7fffffffdfb0):
[0]: 0x402890 DerivedVirtual::~DerivedVirtual()
[1]: 0x4029a0 DerivedVirtual::~DerivedVirtual()
[2]: 0x402c40 DerivedVirtual::DerivedVirtualPrint()
[3]: 0x402b50 <DerivedVirtual::print() const>
vtable for ‘Base’ @ 0x403c18 (subobject @ 0x7fffffffdfc0):
[0]: 0x4028a0 <virtual thunk to DerivedVirtual::~DerivedVirtual()>
[1]: 0x4029c0 <virtual thunk to DerivedVirtual::~DerivedVirtual()>
[2]: 0x402bc0 <virtual thunk to DerivedVirtual::print() const>
结论:
对象由派生类的vptr、成员数据和基类的vptr、成员数据顺序构成
基类和派生类拥有各自的虚函数表。
菱形继承
class DerivedVirtual1: virtual public Base{
public:
DerivedVirtual1(){}
virtual ~DerivedVirtual1(){}
virtual void DerivedVirtual1Print() { cout<<"DerivedVirtual1Print()"<<endl; }
private:
int m_derivedVirtual1;
};
class DerivedVirtual2: virtual public Base{
public:
DerivedVirtual2(){}
virtual ~DerivedVirtual2(){}
virtual void DerivedVirtual2Print() { cout<<"DerivedVirtual2Print()"<<endl; }
private:
int m_derivedVirtual2;
};
class DerivedLast : public DerivedVirtual1, public DerivedVirtual2{
public:
DerivedLast(){}
virtual ~DerivedLast(){}
virtual void DerivedLastPrint() { cout<<"DerivedLastPrint()"<<endl; }
private:
int m_derivedLast;
};
GDB查看对象如下:
(gdb) p dl
$14 = (DerivedLast) {
DerivedVirtual1> = {
Base> = {
_vptr.Base = 0x403f08 <vtable for DerivedLast+136>,
m_base = 0,
static m_tmp = 1
},
members of DerivedVirtual1:
_vptr.DerivedVirtual1 = 0x403e98 <vtable for DerivedLast+24>,
m_derivedVirtual1 = 0
},
DerivedVirtual2> = {
members of DerivedVirtual2:
_vptr.DerivedVirtual2 = 0x403ed0 <vtable for DerivedLast+80>,
m_derivedVirtual2 = 0
},
members of DerivedLast:
m_derivedLast = 0
}
(gdb) info vtbl dl
vtable for ‘DerivedLast’ @ 0x403e98 (subobject @ 0x7fffffffdfd0):
[0]: 0x4028f0 DerivedLast::~DerivedLast()
[1]: 0x402a30 DerivedLast::~DerivedLast()
[2]: 0x402ee0 DerivedVirtual1::DerivedVirtual1Print()
[3]: 0x402bd0 DerivedLast::DerivedLastPrint()
vtable for ‘DerivedVirtual2’ @ 0x403ed0 (subobject @ 0x7fffffffdfe0):
[0]: 0x402910 <non-virtual thunk to DerivedLast::~DerivedLast()>
[1]: 0x402a50 <non-virtual thunk to DerivedLast::~DerivedLast()>
[2]: 0x402cb0 DerivedVirtual2::DerivedVirtual2Print()
vtable for ‘Base’ @ 0x403f08 (subobject @ 0x7fffffffdff0):
[0]: 0x402920 <virtual thunk to DerivedLast::~DerivedLast()>
[1]: 0x402a60 <virtual thunk to DerivedLast::~DerivedLast()>
[2]: 0x402ae0 <Base::print() const>
结论:
对象由中间类的vptr、成员数据和虚基类的vptr、成员数据顺序构成。
虚基类和中间类拥有虚函数表,最派生类的虚函数表放在第一个中间类的虚函数表中。