您的位置:首页 > 其它

虚函数表剖析(借助gdb和vc工具)

2016-05-04 20:47 204 查看

问题

之前分析了c++中的类成员函数的重载、隐藏和覆盖之间的关系,我们从概念上有了清晰的区分,主要是分析覆盖与隐藏之间的关系,但是当子类的函数隐藏了基类的同名虚函数时,我并不清楚具体的实现机制是什么,我们都知道虚函数的调用发生在运行时期,每个类如果存在虚函数则就有相应的虚函数表,但在基类的虚函数被隐藏时,派生类的虚函数表中是否存在被隐藏的基类虚函数的指针,以及如何对虚函数表中的函数的查看,下面进行分析。

class Base
{
public:
virtual void func()
{
cout << "Base :" << endl;
}
virtual void func(int arg1)
{
cout << "Base :" << arg1 << endl;
}
void func(int arg1,int arg2)
{
cout << "Base :" << arg1 <<": "<< arg2 << endl;
}
};
class A: public Base
{
public:
void func()
{
cout << "A :" << endl;
}
virtual void func1(){}
};
int main()
{
Base base;
A a;
Base *test =&a;
test->func();// 重载
//a.func(1);// 隐藏,编译错误
//a.func(1,2);//编译错误
test->func(1); // Base::func(int);
}


上面的例子中,派生类A中的func()覆盖了Base类中的func()的同时,也隐藏了其它两个同名的函数。因此会出现编译错误,但是当将a转换为Base指针时可以调用隐藏的函数,因此不知道此时调用的虚函数是父类还是基类的虚函数表,如何查看此时派生类虚函数表中的函数指针

分析

毫无疑问,我们知道Base中的虚函数表是一个函数指针数组,每一个虚函数指针占用虚函数表中的一个位置,具体32位机器是4个字节,64位8个字节。



这是对象base中的虚函数分布,右边为Base类的虚函数表。每个有虚函数的类的对象为了访问虚函数方便,基本上都将虚函数表的指针放在对象的最开头,因此我们可以通过表达式(int*)*(int*)&a得到虚函数表的指针。本例中只是为了说明没有设置成员变量,因此对象的其它成员是空的。

typedef void (*func)();
cout << "虚函数表地址:" << ((int*)*(int*)(&base)) << endl;
cout << "第一个函数表地址:" << (*((int*)*(int*)(&base))) << endl;
func pFunc = (func)(*((int*)*(int*)(&base)));
pFunc();


获得了函数指针,按照上面的方式,我们可以直接对类成员函数进行访问(基于c++对于指针的强大的处理能力,当然这是违反原则的),可以说c++是集于天使和魔鬼于一生。。但是当试着访问带参数的func(int)在函数返回时会出现ESP错误,不知道什么缘故,反正只是为了探明真相,实际中并不会这样应用的。

但是派生类中的虚函数是怎么样的呢,下面利用vc和gdb进行查看

查看

vc查看

在debug模式下可以查看对象的虚函数表指针,和虚函数表内容。



可以看到:

派生类的func()覆盖了基类的func().

虽然基类的同名虚函数func(int)被隐藏,但是在派生类虚函数表中依然可以看到基类的func(int)虚函数的指针

但是可以看到的是,派生类中自定义的func1()却没有显示出来,因此vc查看到的是不完整的。

gdb查看

在vc下面查看派生类自定义的虚函数无法看到,因此可以在linux下利用gdb来查看:



同时可以利用:info line #linenum 来查看函数的地址



上面可以很清楚的看到派生类A中的虚函数表的内容,同时也可以看到函数的具体地址。

对象a的虚函数表:



结论

虽然派生类会隐藏基类中的虚函数,但是在派生类的虚函数表中依然存在基类的虚函数指针,只不过在编译检查时,基于隐藏的原则提示编译错误。

借助于VC可以查看虚函数表,但是对于子类的虚函数表显示并不完整, 只会显示基类的虚函数的部分。

基于gdb我们可以查看整个虚函数表的内容,注意的是系统的位数不同函数指针所占的字节也不同。

本文只是查看了单继承的虚函数表,借助gdb我们就可以查看具体的复杂继承情况。

参考

/article/2551883.html

/article/5196722.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: