先来查看一简单例子
  1. #include<iostream>
  2. using namespace std;
  3. class Base{
  4. public:
  5. virtual void f() { cout << "base f()被call"<<endl; }
  6. virtual void g() { cout << "父类虚函数G被call" << endl; }
  7. };
  8. class Derive : public Base{
  9. public:
  10. virtual void f() { cout << "子类虚函数f()被call" << endl; }
  11. };
  12. int main()
  13. {
  14. Derive d; //子类对象
  15. Base *pb;//父类指针
  16. pb = &d;//父类指针指向子类对象
  17. int *q =(int*) pb;//取出类对象地址
  18. void(*f)(Derive*) = (void(*)(Derive*))(*(int*)(*q));//取出f()函数地址
  19. void(*g)(Derive*) = (void(*)(Derive*))(*(int*)(*q+4));//取出g()函数地址
  20. f((Derive*)pb);//调用子对象虚函数表的第一个元素
  21. g((Derive*)pb);//调用子对象虚函数表的第二个元素
  22. system("pause");
  23. return 0;
  24. }
用VS2015调试一番.查看pb保存子对象的地址.

 以上pb保存了子类对象的地址,地址为0x003bfb64.来看看.这个子类对象的首4个字节(32位机子)地址保存了啥内容(其实是虚函数表的地址)
 .

子类对象首4个字节保存了00948b34这个数值.(这个其实是虚函数表的地址).再来看看这个数值保存了啥内容.

 发现这个地址开始 0094142e跟00941424应该就是虚函数的地址了.不信.咋们到反汇编查看该地址内容.

先查看0x0094142e(函数转为反汇编.其实第一个地址就是跳转).发现没.反汇编已经提示了是Derive::f这个函数
再看看0x00941424.是Base::g这个函数
以上可知.一般编译器实现.把虚函数表的地址用放在子对象首4个字节.虚函数表保存的是虚函数的地址.
  1. void(*f)(Derive*) = (void(*)(Derive*))(*(int*)(*q));//取出f()函数地址
  2. void(*g)(Derive*) = (void(*)(Derive*))(*(int*)(*q+4));//取出g()函数地

比如以上2行.q是子对象的地址.(*q)就是虚函数表的地址 (*q)+4 相当于虚函数的第二个元素的地址. *(int*)(*q)表示第一个虚函数的地址.*(int*)(*q+4));表示第二个虚函数表的地址..最后强制转换为类成员函数.用(void(*)(Derive*).因为一般类成员函数在编译后.首形参是一个this指针.这里用Derive*.因为this指针的类型就是类的类型
  1. f((Derive*)pb);//调用子对象虚函数表的第一个元素
  2. g((Derive*)pb);//调用子对象虚函数表的第二个元素

 最后调用这2个虚函数表中的虚函数.把pb(子对象的地址)当做参数this指针.然后直接调用.即可使得函数被调用了
 
 

 







最新文章

  1. Linux 设置定时任务crontab命令
  2. Salesforce 使用Js 调用Webservice实例
  3. grep命令的使用
  4. SDL教程第一和第二个视频的笔记
  5. web性能优化——浏览器相关
  6. js之函数
  7. Bitmap 之 getPixels() 的 stride
  8. 济南学习 Day 2 T2 pm
  9. mongodb 常见操作转
  10. ID生成器的一种可扩展实现方案
  11. web app开发中 iPhone、iPad默认按钮样式问题
  12. cURL实现get、post请求
  13. WP自定义字体
  14. 没有闲话和grunt.initConfig()
  15. Ajax post数据查询
  16. 《CSS世界》读书笔记(十四)
  17. PHP使用cookie时遇到的坑
  18. eclipse搭建j2ee
  19. mysql rand
  20. Django ORM之QuerySet

热门文章

  1. Java微信公众号开发----关键字自动回复消息
  2. NOIP模拟赛 麻将
  3. C++ 学习笔记(五)类的知识小结一(重载,友元函数,静态成员,new)
  4. Mysql数据库插入中文出现乱码相关
  5. Ping 命令的执行过程和应用协议
  6. 第一课:PHP 文件是什么?
  7. gulp的安装和使用
  8. 使用fio测试磁盘I/O性能
  9. .Net Task常见问题
  10. HDU 5468 Puzzled Elena 莫比乌斯反演