关键词搜索

源码搜索 ×
×

深入探讨C++的虚函数表

发布2013-05-15浏览7360次

详情内容

      在本文中,我们来学习C++中的虚函数表。很喜欢苏轼的《题西林壁》:

 

      横看成岭侧成峰,远近高低各不同。

      不识庐山真面目,只缘身在此山中。

 

     这首诗的哲理在于:对于同一个东西,从不同的角度看,结果是不一样的。下面来看一些铺垫性的程序:

 

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. float f = 3.14;
  6. cout << f << endl; // 3.14
  7. cout << &f << endl; // 0012FF7C
  8. cout << (int *)(&f) << endl; // 0012FF7C
  9. cout << *((int *)(&f)) << endl; // 1078523331
  10. return 0;
  11. }
  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. float **pp;
  6. float *p;
  7. float a = 10.5;
  8. p = &a;
  9. pp = &p;
  10. cout << pp << endl; // 0012FF78
  11. cout << p << endl; // 0012FF74
  12. cout << a << endl; // 10.5
  13. cout << "---------" << endl;
  14. #define ADDR 0x0012ff78
  15. cout << (float **)ADDR << endl; // 0012FF78
  16. cout << *(float **)ADDR << endl; // 0012FF74
  17. cout << *(*(float **)ADDR) << endl; // 10.5
  18. cout << "---------" << endl;
  19. cout << (int **)ADDR << endl; // 0012FF78
  20. cout << *(int **)ADDR << endl; // 0012FF74
  21. cout << *(*(int **)ADDR) << endl; // 1093140480
  22. cout << *((float *)(*(int **)ADDR)) << endl; // 10.5
  23. cout << "---------" << endl;
  24. return 0;
  25. }
  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. cout << (short *)0 + 1 << endl; // 00000002
  6. cout << (int *)0 + 1 << endl; // 00000004
  7. cout << (long *)0 + 1 << endl; // 00000004
  8. cout << (float *)0 + 1 << endl; // 00000004
  9. cout << (double *)0 + 1 << endl; // 00000008
  10. return 0;
  11. }

 

       搞懂了上面三个程序,就弄懂了苏轼的那首诗。同样的内存单元,不同的解析方式,可以得到不同的结果,下面来进入虚函数表的话题。看程序:

 

  1. #include <iostream>
  2. using namespace std;
  3. class A
  4. {
  5. public:
  6. virtual void fun();
  7. };
  8. int main()
  9. {
  10. cout << sizeof(A) << endl; // 4
  11. return 0;
  12. }

     古怪,结果怎么会是4呢?这是虚指针在作怪!哪来的虚指针哦?看下面的程序:

 

 

  1. #include <iostream>
  2. using namespace std;
  3. class E
  4. {
  5. public:
  6. // 为了方便叙述,故把公开a和b, 在实际系统中,很少这样做
  7. int a;
  8. int b;
  9. virtual void f()
  10. {
  11. };
  12. virtual void g()
  13. {
  14. };
  15. };
  16. int main()
  17. {
  18. E e;
  19. e.a = 1;
  20. e.b = 2;
  21. cout << &e << endl; // e的VTABLE的地址: 0012FF74
  22. cout << (int *)&e << endl; // eVPTR的地址: 0012FF74
  23. cout << &e.a << endl; // e.a的地址: 0012FF78
  24. cout << &e.b << endl; // e.b的地址: 0012FF7C
  25. cout << (void *)*((int *)&e) << endl; // eVPTR的值 0046F028
  26. cout << *((int *)&e + 1) << endl; // e.a的值: 1
  27. cout << *((int *)&e + 2) << endl; // e.b的值: 2
  28. cout << (void *)*(int *)(*(int *)&e) << endl; // E的f函数的地址: 0040128A
  29. cout << (void *)*((int *)(*(int *)&e) + 1) << endl; // E的g函数的地址: 004011B8
  30. cout << "---------" << endl;
  31. E ee;
  32. ee.a = 3;
  33. ee.b = 4;
  34. cout << &ee << endl; // ee的VTABLE的地址: 0012FF68
  35. cout << (int *)&ee << endl; // eeVPTR的地址: 0012FF68
  36. cout << &ee.a << endl; // ee.a的地址: 0012FF6C
  37. cout << &ee.b << endl; // ee.b的地址: 0012FF70
  38. cout << (void *)*((int *)&ee) << endl; // eVPTR的值 0046F028
  39. cout << *((int *)&ee + 1) << endl; // ee.a的值: 3
  40. cout << *((int *)&ee + 2) << endl; // ee.b的值: 4
  41. cout << (void *)*(int *)(*(int *)&ee) << endl; // E的f函数的地址: 0040128A
  42. cout << (void *)*((int *)(*(int *)&ee) + 1) << endl; // E的g函数的地址: 004011B8
  43. return 0;
  44. }

      这个程序稍微有点复杂,下面,我们来画图分析:

 



        我们调试上述程序,得到下图:

       上述三个图,交相辉映,现在,有点明白虚函数表了吧。
 

相关技术文章

点击QQ咨询
开通会员
返回顶部
×
微信扫码支付
微信扫码支付
确定支付下载
请使用微信描二维码支付
×

提示信息

×

选择支付方式

  • 微信支付
  • 支付宝付款
确定支付下载