gcc下c++对象模型,对象内存分布

GCC对象内存布局(win10)

gdb调试的一些用法:
C:\Users\huangx\Desktop\Test> g++ -std=c++11 -g -o test test.cpp //-g 加入调试信息
C:\Users\huangx\Desktop\Test> gdb test //进入调试
(gdb) set p pretty on //美化print的输出
(gdb) b 47 //break line设置断点
(gdb) r //run 运行程序
(gdb) p d //打印对象d的布局
(gdb) x/nfu <address> //examine 查看内存布局 n是要查看内存单元的个数,f是显示的格式(x十六进制),u是字节个数(g八字节),从<address>开始显示。
1,单、多继承,无虚基类、虚函数

源代码

#include <iostream>
#include <typeinfo>
/*

    单继承、多继承
    无虚继承、虚函数

*/
class Base{
public:
    int vla1 = 1;
};

class  Derived1:public Base{
    
public:
    int val2 = 2;

};

class Derived2:public Base {
public:
    int val3 = 3;
};

class Derived:public Derived1,public Derived2{
public:
    int val = 4;
};

int main(){
    Derived1 d1;
    Derived d;
    return 0;
}

结构

在这里插入图片描述

内存布局(一格代表四个字节)
在这里插入图片描述

(gdb) p d
$1 = {
  <Derived1> = {
    <Base> = {
      vla1 = 1
    },
    members of Derived1:
    val2 = 2
  },
  <Derived2> = {
    <Base> = {
      vla1 = 1
    },
    members of Derived2:
    val3 = 3
  },
  members of Derived:
  val = 4
}

(gdb) p sizeof(d)
$2 = 20
//win是小端对齐,所以看起来2和3在1的前面    
(gdb) x/10xg &d
0x61fdf0:       0x0000000200000001      0x0000000300000001
0x61fe00:       0x0000000000000004      0x0000000100000032
0x61fe10:       0x0000000a00000002      0x0000000200000001
0x61fe20:       0x00000000001c1850      0x00000000004013c7
0x61fe30:       0x0000000000000000      0x0000000000000032
2,单继承,有虚基类,无虚函数

源代码

#include <iostream>
#include <typeinfo>

/*

    单虚继承,无虚函数

*/
class Base{
public:
    int vla1 = 1;
};


class  Derived1:virtual public Base{
    
public:
    int val2 = 2;

};

class Derived2:virtual public Derived1 {
public:
    int val3 = 3;
};

int main(){

    Derived1 d1;
    auto vptr_Derived1 = (int*)*(int*)&d1;

/*  std::cout << *(vptr_Derived1-6) << std::endl;   //  Vbase_offset
    std::cout << *(vptr_Derived1-4) << std::endl; //  top_offset
    std::cout << *(vptr_Derived1-2) << std::endl; //  ptr type_info */
    
    std::type_info* t1 = (std::type_info *)*(vptr_Derived1-2);
    std::cout << t1->name() << std::endl; //Derived

    Derived2 d2;

    return 0;
}

结构
在这里插入图片描述

内存布局

在这里插入图片描述

(gdb) p d2
$1 = {
  <Derived1> = {
    <Base> = {
      vla1 = 1
    },
    members of Derived1:
    _vptr.Derived1 = 0x404608 <vtable for Derived2+56>,
    val2 = 2
  },
  members of Derived2:
  _vptr.Derived2 = 0x4045f0 <vtable for Derived2+32>,
  val3 = 3
}
(gdb) p sizeof(d2)
$2 = 32

(gdb) x/10xg &d2
0x61fde0:       0x00000000004045f0      0x0000000000000003
0x61fdf0:       0x0000000000404608      0x0000000100000002
0x61fe00:       0x00000000004045c8      0x0000000100000002
0x61fe10:       0x00000000004044f0      0x00000000004045c8
0x61fe20:       0x0000000000d61850      0x00000000004013c7
    
(gdb) x/10xg 0x4045d0
0x4045d0 <_ZTV8Derived2>:       0x000000000000001c      0x0000000000000010
0x4045e0 <_ZTV8Derived2+16>:    0x0000000000000000      0x0000000000404520
0x4045f0 <_ZTV8Derived2+32>:    0x000000000000000c      0xfffffffffffffff0
0x404600 <_ZTV8Derived2+48>:    0x0000000000404520      0x0000000000000000
0x404610 <_ZTV8Derived2+64>:    0x387828203a434347      0x736f702d34365f36

3,多继承,有虚基类,无虚函数

多重虚继承内存中只存在有一个基类

源代码

#include <iostream>
#include <typeinfo>

/*

    多继承一个虚基类,无虚函数

*/

class Base{
public:
    int vla1 = 32;
};

class  Derived1:virtual public Base{
    
public:
    int val2 = 2;

};

class Derived2:virtual public Base{
public:
    int val3 = 3;
};

class Derived:public Derived1,public Derived2{
public:
    int val4 = 4;
};

int main(){

    Derived d;

    return 0;
}

结构

在这里插入图片描述

内存布局
在这里插入图片描述

(gdb) p d
$1 = {
  <Derived1> = {
    <Base> = {
      vla1 = 32
    },
    members of Derived1:
    _vptr.Derived1 = 0x404608 <vtable for Derived+24>,
    val2 = 2
  },
  <Derived2> = {
    members of Derived2:
    _vptr.Derived2 = 0x404620 <vtable for Derived+48>,
    val3 = 3
  },
  members of Derived:
  val4 = 4
}
(gdb) p sizeof(d)
$2 = 40

(gdb) x/10xg &d
0x61fdf0:       0x0000000000404608      0x0000000000000002
0x61fe00:       0x0000000000404620      0x0000000400000003
0x61fe10:       0x0000000000000020      0x0000000000000010
0x61fe20:       0x0000000000731850      0x00000000004013c7
0x61fe30:       0x0000000000000000      0x0000000000000036

(gdb) x/10xg 0x4045f0
0x4045f0 <_ZTV7Derived>:        0x0000000000000020      0x0000000000000000
0x404600 <_ZTV7Derived+16>:     0x00000000004044f0      0x0000000000000010
0x404610 <_ZTV7Derived+32>:     0xfffffffffffffff0      0x00000000004044f0
0x404620 <_ZTV7Derived+48>:     0x387828203a434347      0x736f702d34365f36
0x404630 <_ZTV7Derived+64>:     0x722d6865732d7869      0x697542202c307665
4,单继承,有虚基类,有虚函数

源代码

#include <iostream>
#include <typeinfo>
/*

    单继承,有虚继承、有虚函数

*/
class Base{
public:
    int vla1 = 8;
    virtual void get(){
        std::cout << "b" << std::endl;
    }
};

class  Derived1:virtual public Base{
public:
    int val2 = 32;
    virtual void get()override{
        std::cout << "d1" << std::endl;
    }

};

int main(){
    Derived1 *d1 = new Derived1;
    Base *b1 = d1;
    Base &b2 = *d1;

    return 0;
}

结构

在这里插入图片描述

内存

在这里插入图片描述

发生多态时,编译器将自动调整基类指针的指向(指向派生类对象的subobject所在),因此我们无法通过基类指针获取派生类静态绑定的成员。当然知道了布局之后,可以通过内存可以获取。

当调用虚函数时,通过虚表指针v_base找到thunk,经编译器调整后调用动态绑定的对象的虚函数。

(gdb) p  *d1
$1 = {
  <Base> = {
    _vptr.Base = 0x404588 <vtable for Derived1+56>,
    vla1 = 8
  },
  members of Derived1:
  _vptr.Derived1 = 0x404568 <vtable for Derived1+24>,
  val2 = 32
}
(gdb) p sizeof(*d1)
$10 = 32
(gdb) x/4xg d1 //可能编译器不会把用来填充的字节初始化吧...
0xf51b60:       0x0000000000404568      0xbaadf00d00000020
0xf51b70:       0x0000000000404588      0xbaadf00d00000008  
    
    
(gdb) p *b1
$2 = {
  _vptr.Base = 0x404588 <vtable for Derived1+56>,
  vla1 = 8
}
(gdb) p b1
$3 = (Base *) 0xf51b70
(gdb) p b2
$4 = (Base &) @0xf51b70: {
  _vptr.Base = 0x404588 <vtable for Derived1+56>,
  vla1 = 8
}


(gdb) x/10xg 0x404550
0x404550 <_ZTV8Derived1>:       0x0000000000000010      0x0000000000000000
0x404560 <_ZTV8Derived1+16>:    0x00000000004044d0      0x0000000000402d90
0x404570 <_ZTV8Derived1+32>:    0xfffffffffffffff0      0xfffffffffffffff0
0x404580 <_ZTV8Derived1+48>:    0x00000000004044d0      0x0000000000402e20
0x404590 <_ZTV8Derived1+64>:    0x387828203a434347      0x736f702d34365f36
5,多重继承,有虚继承,有虚函数

源代码

#include <iostream>
#include <typeinfo>
typedef void (*Pfun)();

/*

    单继承、多继承
    有虚继承、有虚函数

*/
class Base{
public:
    int vla1 = 8;
    virtual void get(){
        std::cout << "b" << std::endl;
    };
};

class  Derived1:virtual public Base{
    
public:
    int val2 = 32;
    virtual void get()override{
        std::cout << "d1: "  << std::endl;
    };

};

class Derived2:virtual public Base{
public:
    int val3 = 48;
    virtual void get()override{std::cout << "d2" << std::endl;};
};

class Derived:public Derived1,public Derived2{
public:
    int val4 = 16;
    virtual void get()override{std::cout << "d" << std::endl;};
};

int main(){
    Derived *d = new Derived;
    Derived1 *d1 = d;
    Derived2 &d2 = *d;
    Base &b = *d;
    std::cout << "???" << std::endl;
    Pfun f1 = (Pfun)(int*)*(int*)*((int*)d+4);
    Pfun f2 = (Pfun)(int*)*(int*)*((int*)d+8);

    return 0;
}

结构
在这里插入图片描述

内存
在这里插入图片描述

(gdb) p *d
$14 = {
  <Derived1> = {
    <Base> = {
      _vptr.Base = 0x405708 <vtable for Derived+88>,
      vla1 = 8
    },
    members of Derived1:
    _vptr.Derived1 = 0x4056c8 <vtable for Derived+24>,
    val2 = 32
  },
  <Derived2> = {
    members of Derived2:
    _vptr.Derived2 = 0x4056e8 <vtable for Derived+56>,
    val3 = 48
  },
  members of Derived:
  val4 = 16
}
(gdb) p d
$9 = (Derived *) 0x1d1b60
(gdb) p d1
$10 = (Derived1 *) 0x1d1b60
(gdb) p &d2
$11 = (Derived2 *) 0x1d1b70
(gdb) p &b
$13 = (Base *) 0x1d1b80
    
    
(gdb) p sizeof(*d)
$3 = 48
(gdb) x/6xg d
0x1d1b60:       0x00000000004056c8      0xbaadf00d00000020
0x1d1b70:       0x00000000004056e8      0x0000001000000030
0x1d1b80:       0x0000000000405708      0xbaadf00d00000008
(gdb) p f1
$1 = (Pfun) 0x402fb0 <non-virtual thunk to Derived::get()>
(gdb) p f2
$2 = (Pfun) 0x402fc0 <virtual thunk to Derived::get()>
    
(gdb) x/12xg 0x4056b0  ///可能虚基类的vbase_offset没用吧..
0x4056b0 <_ZTV7Derived>:        0x0000000000000020      0x0000000000000000
0x4056c0 <_ZTV7Derived+16>:     0x0000000000405570      0x0000000000402dc0
0x4056d0 <_ZTV7Derived+32>:     0x0000000000000010      0xfffffffffffffff0
0x4056e0 <_ZTV7Derived+48>:     0x0000000000405570      0x0000000000402fb0
0x4056f0 <_ZTV7Derived+64>:     0xffffffffffffffe0      0xffffffffffffffe0
0x405700 <_ZTV7Derived+80>:     0x0000000000405570      0x0000000000402fc0
最后

还有很多地方没有深究…比如thunk…

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值