C++程序运行时内存布局之----------无继承情况下的虚函数

来源:互联网 发布:淘宝付款时间限制 编辑:程序博客网 时间:2024/04/30 16:07

本文转自 http://blog.csdn.net/smstong/article/details/6584026


虚函数是C++实现多态的关键,没有虚函数,C++只能是OB,不能完成OO。对于VC++中虚函数的实现机制,有很多文章,我看过的是陈浩写的,链接如下:

http://blog.csdn.net/haoel/article/details/1948051。总觉得还是有些不太清楚的,所以自己做了进一步的实验,记录下来以供参考。

本文介绍的是没有继承情况下,带有虚函数的类在内存中布局,以及其实例(对象)内存布局。

 

1.源码

view plain
  1. #include <iostream>  
  2. #include <stdio.h>  
  3.   
  4. using namespace std;  
  5.   
  6. class CVirtual  
  7. {  
  8. public:  
  9.     int x;  
  10. public:  
  11.     virtual void VF()  
  12.     {  
  13.         cout<<this->x<<endl;  
  14.         cout<<"hello"<<endl;  
  15.     }  
  16. public:  
  17.     CVirtual(int x)  
  18.     {  
  19.         this->x = x;  
  20.     }  
  21. };  
  22.   
  23. typedef void (CVirtual::*Fun)();  
  24. union  
  25. {  
  26.     Fun f;  
  27.     unsigned int addr;  
  28. }ut;  
  29.   
  30. int main(int argc, char** argv)  
  31. {  
  32.     //打印出类实例的大小  
  33.     cout<<"对象大小为                       :"<<sizeof(CVirtual)<<endl;  
  34.   
  35.     CVirtual *p = new CVirtual(999);  
  36.     CVirtual *p1 = new CVirtual(888);  
  37.   
  38.     //打印对象地址  
  39.     cout<<"新建对象的地址                   :"<<p<<endl;  
  40.   
  41.     //打印第一个成员变量地址  
  42.     cout<<"对象中第一个成员变量的地址       :"<<&p->x<<endl;  
  43.   
  44.     //打印虚函数的地址  
  45.     ut.f = &(CVirtual::VF);  
  46.     cout<<"类中第一个虚函数的地址           :"<<std::hex<<std::showbase<<ut.addr<<endl;  
  47.   
  48.     //虚表指针  
  49.     unsigned int vptr = *((unsigned int*)p);  
  50.     cout<<"对象1中虚表指针(即虚表地址)为    :"<<std::hex<<std::showbase<<vptr<<endl;  
  51.   
  52.     //虚表第一项值为  
  53.     unsigned slot0 = *((unsigned int*)vptr);  
  54.     cout<<"虚表中第一项的值(第一个虚函数地址):"<<std::hex<<std::showbase<<slot0<<endl;  
  55.   
  56.   
  57.     //虚表指针  
  58.     unsigned int vptr1 = *((unsigned int*)p1);  
  59.     cout<<"对象2中虚表指针(即虚表地址)为    :"<<std::hex<<std::showbase<<vptr1<<endl;  
  60.   
  61.     //虚表第一项值为  
  62.     unsigned slot01 = *((unsigned int*)vptr1);  
  63.     cout<<"虚表中第一项的值(第一个虚函数地址):"<<std::hex<<std::showbase<<slot01<<endl;  
  64.   
  65.   
  66.     //虚函数的原型  
  67.     typedef void (__thiscall *MyFun)(void* pThis);  
  68.   
  69.     //调用虚函数表中的第一个函数  
  70.     MyFun f = (MyFun)slot0;  
  71.     f(p);  
  72.   
  73.     //调用虚函数  
  74.     MyFun f1 = (MyFun)ut.addr;  
  75.     f1(p);  
  76.   
  77.     delete p;  
  78.     delete p1;   
  79.     cin>>argc;  
  80. }  

 

2.结果

 

3.内存布局图

4.结论

  • 虚函数表在编译期间已经确定,建立在data区,运行期只是把由构造函数把对象的vptr值设定为这个地址,同一个类的所有实例共享同一个虚函数表;
  • 虚函数表中的每一个项目不一定是虚函数的地址,很可能是一个代理函数,然后由代理函数再调用虚函数;

原创粉丝点击