当前位置:编程学习 > C/C++ >>

C++虚函数表解析 [二]

 

虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。在这个表中,主要是一个类的虚函数的地址,这张表解决了继承、覆盖的问题,其内容真实反映了实际函数。这样,在有虚函数的类的实例中虚函数表被分配在实例的内存中,所以,当用父类的指针从操作一个子类的时候,这张虚函数表就显得尤为重要了,它就像一张地图,指明了实际所应该调用的函数。

 

在C++的标准规格说明书中写道,编译器必须保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证正确取到虚函数的偏移量)。这意味着通过对象实例的地址可以得到虚函数表,然后可以遍历其中的函数指针,并调用相应的函数了。请看下面的代码

 

class Base{ 

public: 

    virtual void fun1(){cout<<"Base::fun1"<<endl;} 

    virtual void fun2(){cout<<"Base::fun2"<<endl;} 

    virtual void fun3(){cout<<"Base::fun3"<<endl;} 

private: 

    int num1; 

    int num2;  

 

}; 

typedef void(*Fun)(void); 

int main(int argc, char* argv[]) 

   Base b; 

   Fun pFun; 

   pFun=(Fun)*((int*)*(int*)(&b)+0); 

   pFun(); 

   pFun=(Fun)*((int*)*(int*)(&b)+1); 

   pFun(); 

   pFun=(Fun)*((int*)*(int*)(&b)+2); 

   pFun(); 

   return 0; 

上面程序的执行结果如下:

 

 

 

 

Base::fun1

 

Base::fun2

 

Base::fun3

 

 

可以看到通过函数指针pFun的调用,分别执行了对象b的3个虚函数。通过这个示例发现,可以强行把&b转成int*,取得虚函数表的地址,然后再次取址就可以得到第一个虚函数的地址了,也就是Base::fun1()。如果调用Base::fun2()和Base::fun3(),只需要把&b先加上数组元素的偏移,后面的步骤类似。

 

程序中Base对象b的内存结构图,如下图所示:

\

 

摘自:日新为道的专栏

补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,