查看虚函数表

   关于虚函数表的介绍:http://blog.youkuaiyun.com/haoel/article/details/1948051/
                                      http://blog.youkuaiyun.com/hackbuteer1/article/details/7883531

上网搜了半天,没找到好的,自己看了一下,在linux的gdb环境下有比较简单的方法可以看
在blog里记录一下,免得自己忘了

1. 查看函数地址
    看函数在代码的哪一行,使用info line就可以看到类似下面这中输出

点击(此处)折叠或打开

  1. (gdb) info line a.cpp:10
  2. Line 10 of "a.cpp" starts at address 0x80487d4 <_ZN1B5test2Ev> and ends at 0x80487d7 <_ZN1B5test2Ev+3>.
  3. (gdb) p _ZN1B5test2Ev
  4. $1 = {void (B * const)} 0x80487d4
  5. (gdb)
    可以直接根据函数地址去打断点,当然如果知道文件和行号其实没必要拐个弯来打这种费解的断点,应用场合更多是想使用汇编调试的时候。

点击(此处)折叠或打开

  1. 16 public:
  2. 17 virtual void test2(){
  3. 18 cout << "If I'm lying, I'm crying!" << endl;
  4. 19 }
  5. 20
  6. (gdb) info line 17
  7. Line 17 of "a.cpp" starts at address 0x8048808 <_ZN1D5test2Ev> and ends at 0x804880e <_ZN1D5test2Ev+6>.
  8. (gdb) b *0x804880e
  9. Note: breakpoint 2 also set at pc 0x804880e.
  10. Breakpoint 3 at 0x804880e: file a.cpp, line 18.


2. 查看虚函数表
    如果仅仅是想知道当前对象的真实类别,那使用这句就可以看到了(示例里面的b实际上是D类对象,而非B类)。

点击(此处)折叠或打开

  1. (gdb) set print object on
  2. (gdb) p b
  3. $3 = (D &) @0xbfe3116c: { = {_vptr.B = 0x8048948}, }

    查看对象里面的虚指针,也很简单,把虚指针指向的内容显示一下就可以了。

点击(此处)折叠或打开

  1. (gdb) p b
  2. $6 = (D &) @0xbfe3116c: { = {_vptr.B = 0x8048948}, }
  3. (gdb) p /a *(void**)0x8048948@2
  4. $7 = {0x8048834 <_ZN1D4testEv>, 0x8048808 <_ZN1D5test2Ev>}
    查看虚表的前面,会发现g++实现的时候将RTTI信息放到虚函数表的前面一点点了。反汇编查看代码其实也可以发现的,typeid会根据虚表指针偏移一下去找RTTI信息。

点击(此处)折叠或打开

  1. (gdb) p /a *((void**)0x8048948-1)
  2. $18 = 0x8048950 <_ZTI1D>

点击(此处)折叠或打开

  1. sles10sp1:~/test # c++filt _ZTI1D
  2. typeinfo for D

PS:
    在VC的IDE环境中的Debug状态下展开类的实例也可以看到虚函数表。
    C++的多态是基于虚指针来实现的,如果不小心导致虚指针的值被改写了(最常见的错误就是对一个包含虚指针的对象执行了memset操作),就可能导致程序core掉。
    而调用虚函数、使用dynamic_cast以及typeid都会使用到虚指针,所以当程序core这些需要在呈现多态的地方,不必感到太惊讶。
    另外大多数编译器对虚指针的赋值是在构造函数里面进行的,而这部分赋值代码是编译器自行插入的。

<think>嗯,用户问的是如何在VisualStudio中查看C++的虚函数表或者vtable布局。我需要结合之前的引用内容来回答这个问题。首先,我记得引用[4]和[5]提到了使用VS的调试器来查看虚函数表,还有设置断点和监视窗口的方法。用户可能需要具体的步骤,所以得详细说明操作流程。首先,应该分步骤解释如何在调试模式下查看虚函数表。比如设置断点,运行到断点处,然后在局部变量窗口中找到对象的_vfptr。引用[4]提到可能需要添加监视,并调整数组长度才能看到所有虚函数条目,这点很重要,用户可能会遇到显示不全的问题,所以需要特别指出。 另外,引用[5]提到查看类内存布局的方法,可能需要使用VS的开发者命令提示符来执行命令,比如使用d1reportSingleClassLayout选项。这部分需要给出具体的编译命令,告诉用户如何在项目属性里设置编译器选项,这样他们才能生成内存布局的报告。还有,用户可能需要知道如何确认虚函数表是否正确,比如通过调用虚函数并观察输出,这可以作为辅助方法。不过用户主要问题还是查看vtable,所以这部分可以简要提及。需要确保回答结构清晰,分点说明,每个方法都给出步骤,并引用相关的引用资料。同时,用户可能对为什么虚函数表显示不全有疑问,所以解释需要调整监视窗口的设置,比如修改数组长度,这部分要详细说明。 最后,生成相关问题的时候,可以围绕虚函数表结构、动态绑定机制、内存布局的影响因素,以及不同编译器的查看方法展开。这样用户如果有进一步的问题,可以继续探索。</think>在Visual Studio中查看C++虚函数表(vtable)布局的步骤如下: ### 方法一:通过调试器查看 1. **设置断点** 在包含虚函数调用的代码行设置断点(如`basePtr->show()`处) 2. **启动调试** 按F5进入调试模式,程序将在断点处暂停 3. **查看虚表指针** 在调试窗口的"局部变量"面板中展开对象实例: ``` > basePtr > [Base] > _vfptr -> 0x... (地址) ``` 4. **监视虚函数表** 右击`_vfptr`选择"添加监视",修改监视表达式为: ```cpp (*(void***)&basePtr),5 // 5表示查看前5个条目 ``` 此时会显示虚函数地址列表[^4][^5] ### 方法二:查看内存布局 1. **设置编译器选项** 在项目属性 -> C/C++ -> 命令行中添加: ```bash /d1reportSingleClassLayout类名 ``` 例如查看`Derived`类: ```bash /d1reportSingleClassLayoutDerived ``` 2. **编译输出** 编译时会在输出窗口显示: ```text class Derived size(...): +--- | +--- (base class Base) | | {vfptr} | +--- +--- ``` 3. **查看虚表内容** 输出中会包含虚函数表条目: ```text Derived::$vftable@: 0 | &Derived::show ```[^2][^5] ### 方法三:通过内存窗口 1. 调试时打开"内存1"窗口 2. 输入`&basePtr`查看对象起始地址 3. 前4字节(x86)或8字节(x64)即为虚表指针 4. 跳转到该地址可查看虚函数指针数组
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值