GDB查看C++对象布局

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、成员数据顺序构成。
虚基类和中间类拥有虚函数表,最派生类的虚函数表放在第一个中间类的虚函数表中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值