查看C++虚函数表

2 篇文章 0 订阅

1. 使用Visual Studio查看虚函数表

1.1 方法一:使用调试器查看虚函数表

使用VS设置断点并执行调试,在VS的调试器的局部变量可以看到b::A::_vfptr 虚函数表变量,如下图
在这里插入图片描述
但是,这里有个问题,照理说 b 中应该有4个虚函数(其中A::funa()class B 中被重载,所以只剩下4个)外加一个结束标志,从B::vftable[5]()也可以看到,虚函数表的数组总长度是5,但在这里只显示了2个。这里需要做两步设置

  • 1,右击_vfptr 选择 添加监视 选项
    在这里插入图片描述
  • 2,选择监视面板,双击 (*((A*)&b)).__vfptr,nd 改为 (*((A*)&b)).__vfptr,5(5为数组的物理长度)
    在这里插入图片描述
    结果如下:
    在这里插入图片描述

1.2 方法二:通过命令行查看

项目 > 属性 > C/C++ > 命令行,添加如下内容

/d1 reportAllClassLayout [XXX]
// XXX可选,代表源文件名,例如 main.cpp, 如:/d1 reportAllClassLayout main.cpp/d1 reportSingleClassLayoutXXX
// XXX 代表类名, 如:/d1 reportSingleClassLayoutTest

在这里插入图片描述
重新生成项目,在输出的生成中可以看到如下内容:
在这里插入图片描述

2.使用cgdb查看虚函数表

[root@QingYun cpp]# g++ test.cpp -o test.o -g
[root@QingYun cpp]# cgdb test.o
...
(gdb) b	main
Breakpoint 1 at 0x400996: file test.cpp, line 27.
(gdb) run
Starting program: /root/testzone/cpp/test.o
(gdb) n
(gdb) p	b
$1 = {<A> = {_vptr.A = 0x400e70 <vtable for B+16>, a = 4197725, b = 0, d = -7024, e = 32767, c = 0 '\000'}, <No data fields>}
(gdb) p	/a *(void**)0x400e70@5
$2 = {0x400c52 <B::funa()>, 0x400c28 <A::funb()>, 0x400c7c <B::funb1()>, 0x400ca6 <B::func()>, 0x0}

其中 p /a *(void**)0x400e70@5 中的 0x400e70表示虚函数地址表, @5 表示数组长度。

3. test源码

#include <iostream>
using namespace std;

class A {
public:
	virtual void funa() { cout << "Base::funa()" << endl; }
	virtual void funb() { cout << "Base::funb()" << endl; }
	void func() { cout << "Base::func()" << endl; };
private:
	int a;
	int b;
	int d;
	int e;
	char c;
};
class B : public A{
public:
	virtual void funa() { cout << "Driver::funa()" << endl; }
	virtual void funb1() { cout << "Driver::funb1()" << endl; }
	virtual void func() { cout << "Driver::func()" << endl; }
};

// 定义函数指针
typedef void(*FUNC)();	

int main() {
	B b;
	cout << "sizeof(A): " << sizeof(A) << endl;
	cout << "sizeof(B): " << sizeof(B) << endl;
	cout << "Address of b: " << &b << endl;
	
	// vptr指向虚函数表
	void* vptr = *(void**)(&b);	
	cout << "address of vtable: " << vptr << endl;

	// 取虚函数表的第一个元素,并执行
	FUNC p_fun = (FUNC)(*(void**)vptr);	
	cout << "address of function: " << *(unsigned long long*)(p_fun) << endl;
	p_fun();

	// 取虚函数表的第二个元素,并执行
	p_fun = (FUNC)(*((void**)vptr + 1));
	cout << "address of function: " << *(unsigned long long*)(p_fun) << endl;
	p_fun();

	// 取虚函数表的第三个元素,并执行
	p_fun = (FUNC)(*((void**)vptr + 2));
	cout << "address of function: " << *(unsigned long long*)(p_fun) << endl;
	p_fun();

	// 取虚函数表的第四个元素,并执行
	p_fun = (FUNC)(*((void**)vptr + 3));
	cout << "address of function: " << *(unsigned long long*)(p_fun) << endl;
	p_fun();

	// 取虚函数表的第五个元素,并执行(实际上第五个是结束标志\0,所以会失败)
	p_fun = (FUNC)(*((void**)vptr + 4));
	cout << "address of function: " << *(unsigned long long*)(p_fun) << endl;
	p_fun();

	return 0;
}

参考
https://blog.csdn.net/ztguang/article/details/51015760
https://www.cnblogs.com/cheungxiongwei/p/9364773.html

另外,关于虚函数,这里还有一篇很好的文章:https://www.cnblogs.com/yunlambert/p/9876491.html

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值