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