C++虚函数表

Visual Studio调试技巧

我们使用Visual Studio工具来查看C++对象的内存布局,所以需要在当前项目上右键单击选择“属性”后,打开属性页,在配置属性->C/C+±>命令行下的其它选项文本框中配置如下命令:

/d1 reportAllClassLayout

在“调试”中选“输出”,然后在下来框中选“生成”

无虚函数

/*
Base1.cpp
*/
class Base1
{
   
   
    public:
        int base1_1;
        int base1_2;

        void base1_fun1() {
   
   }
};

内存分布只有base1_1和base1_2,base1_fun1()函数的内存是在调用时动态分配

此种情况下,内存分布为

-->+------------+
   |  base1_1   |
   +------------+
   |  base1_2   |
   +------------+

单个类,没继承

/*
Base1.cpp
*/
class Base1
{
    public:
        int base1_1;
        int base1_2;

        virtual void base1_fun1() {}
        virtual void base1_fun2() {}

};
/*
main.cpp
*/
#include "Base1.cpp"
int main()
{
    Base1* b1 = new Base1();
    b1->base1_fun1();
    return 0;
}

反汇编之后的结果

 b1->base1_fun1();
007219D7  mov         eax,dword ptr [b1]  //把b1地址的值赋值给eax
007219DA  mov         edx,dword ptr [eax] //把eax对应的内存地址上的值赋值给edx,即edx内保存b1所对内存的地址
007219DC  mov         esi,esp  
007219DE  mov         ecx,dword ptr [b1]  //b1对应内存的地址赋值给ecx
007219E1  mov         eax,dword ptr [edx] //edx对应内存的地址,即b1指针赋值给eax
007219E3  call        eax                 //调用eax

总的来说,就是b1的首地址给eax,call eax就是调用base1_fun1()

结合vs2019上的变量监视以及类对象内存结构分析可知,b1的首地址保存的是虚函数表(__vfptr)

__vfptr的类型是void**,因此,指向的是一个数组,该数组的内部是 void * 对象,即

__vfprt-->+--------+
          | void * |
          +--------+
          | void * |
          +--------+

根据上述的代码可知

__vfptr --> +--------------+
            | base1_func1()|
            +--------------+

GDB调试

为了方便,将上面的堆分配改为栈分配

/*
main.cpp
*/
#include "Base1.cpp"
int main()
{
   
   
    Base1 b1;
    b1.base1_fun1();
    return 0;
}

首先用g++进行编译

g++ base.h main.cpp -g

然后用gdb进行调试

gdb ./a.out
b main

将断点停在b1.base1_func1()

然后用gdb查看内存变化
在这里插入图片描述

可以看一下ZTV4Base是什么
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值