虚函数表地址的打印
这段时间由于面试的一个问题(虚函数的实现原理),算是认真的看了下虚函数实现的几个介绍,有了一定的认识,简单来说,就是在创建类时,如果函数方法中存在virtual关键字,则认为此成员函数是一个虚函数,此时类对象的内存布局中就会为这个对象创建一个虚函数表,用以实现多态。指向此对象的首地址永远是虚表的指针地址,这样方便多态函数的访问。
这里有一个“地址里的地址的概念”,即指向的内容值,实际也是一个指针的地址值,而这个指针的地址值又是一个函数的首地址,要真正调用到函数的方法,实际用指针搞成了这样,
看,起来很复杂,所以用下面的程序逐个打印解析了下
#include <iostream>
using namespace std;
class Base
{
public:
virtual void foo() {cout << "Base::foo()" << endl;}
};
class Dry : public Base
{
public:
virtual void foo() {cout << "Dry::foo()" << endl;}
};
typedef void (*Fun)(void);
int main()
{
Fun pFun;
Dry d;
cout << &d << endl; // 1、取对象的首地址(为一个地址值),因为虚表指针就是在对象的首地址中存放
cout << (int *)&d << endl; // 2、转换成int型的指针
cout << *(int *)&d << endl; // 3、取值,取出来的是虚表指针的指针值(即指向内容的地址值)
cout << (int *)*(int *)&d << endl; // 4、再转换成int型的指针(主要是为了地址对齐)
cout << *(int *)*(int *)&d << endl; // 5、取出来的虚表指针指向的内容(实际为一个函数的头(又是一个地址-》函数地址))
cout << (Fun)*((int *)*(int *)&d) << endl; // 6、只不过上一步还是int型的,要转换成函数指针的类型:void (Fun *)(void)
cout << "*******************begin testing *******************" << endl;
pFun = (Fun)*((int*)*(int *)(&d)+0);
pFun(); //取到之后,执行函数
return 0;
}
打印后的结果如下:(与程序中打印的结果一一队形)
1、0x61ff08
2、0x61ff08
3、4215204
4、0x4051a4
5、4209992
6、1
*******************begin testing *******************
7、Dry::foo() -----最终调用的函数
解析,这里1/2是一样的,说明是对象的首地址,只是用int转换了下,3/4是一样的,10进制和16机制的转换而已,5才是函数头的指针地址,6、转换成Fun指针后变成了1不是很理解
最后7正确打印函数调用信息。
理解:这里除了6,其他的都很直观,是什么就是什么,只是此处取了3此地址值而已,我想这里要不断的使用int*转换,是因为地址对齐的原因,指针地址值的size正好是int的size
浙公网安备 33010602011771号