(感谢http://blog.csdn.net/haoel/article/details/1948051/)

C++中的虚函数的作用主要是实现了多态的机制。

多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。

虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的,简称为V-Table。在这个表中记录了一个类的虚函数的地址表,这张表解决了继承、覆盖的问题。C++的编译器应该是保证虚函数表的指针存在于对象实例中最前面的位置,所以当我们用父类的指针来操作一个子类的时候,这张虚函数表就像一个地图一样,指明了实际所应该调用的函数。

假设有这样一个基类:

 class Base {
public:
virtual void f() { cout << "Base::f" << endl; }
virtual void g() { cout << "Base::g" << endl; }
virtual void h() { cout << "Base::h" << endl; }
};

在虚函数表的最后有一个结点,这是虚函数表的结束结点,就像字符串的结束符“/0”一样,标志了虚函数表的结束。

 typedef void(*Fun)(void);
Base b;
Fun pFun = NULL; cout << "虚函数表地址:" << (int*)(&b) << endl;
cout << "虚函数表 — 第一个函数地址:" << (int*)*(int*)(&b) << endl; // Invoke the first virtual function
pFun = (Fun)*((int*)*(int*)(&b));
pFun(); (Fun)*((int*)*(int*)(&b)+); // Base::f()
(Fun)*((int*)*(int*)(&b)+); // Base::g()
(Fun)*((int*)*(int*)(&b)+); // Base::h()

可以通过强行把&b转成int *,取得虚函数表的地址,然后,再次取址就可以得到第一个虚函数的地址了,也就是Base::f()。

一般继承(无虚函数覆盖)

子类没有重载任何父类的函数。对于实例Derive d的虚函数表如下:

1)虚函数按照其声明顺序放于表中。

2)父类的虚函数在子类的虚函数前面。

一般继承(有虚函数覆盖)

如果子类中有虚函数重载了父类的虚函数。

1)覆盖的f()函数被放到了虚表中原来父类虚函数的位置。

2)没有被覆盖的函数依旧。

最新文章

  1. JavaScript知识 一、JS的数据类型
  2. 导入CSV格式的数据
  3. c语言 动态数组
  4. 关于2000W数据
  5. C# 之 Stream 和 byte[] 的相关转换
  6. iOS获取webview高度
  7. RedHat9通过Host-only配置网络连接
  8. 9年经验,总结SEO职业瓶颈
  9. javascript 学习资料网址一览
  10. 请教&lt;context:component-scan/&gt;和&lt;mvc:annotation-driven/&gt;的区别20
  11. php中的XML转数组
  12. 8Manage:聚焦研发企业利器——研发项目管理
  13. 创建一个 Spring Boot 项目,你会几种方法?
  14. 译注(2): How to Write a 21st Century Proof
  15. 信用卡欺诈数据的分析-excel篇
  16. flink引出的kafka不同版本的兼容性
  17. day 7-6 GIL,死锁,递归锁与信号量,Event,queue,
  18. ansible和python的zabbix_api批量添加rsync服务的监控
  19. SpringBoot(2) Json框架 -- Jackson返回结果处理
  20. Java知多少(28)super关键字

热门文章

  1. Shell-2-命令之乐
  2. Ubuntu1804登录界面闪退
  3. P2173 [ZJOI2012]网络
  4. Maven入门(二)pom.xml和核心概念
  5. js 点击图片放大,再点击缩小还原
  6. H5切换至后台页面
  7. Hanlp(汉语言处理包)配置、使用、官方文档
  8. BestCoder Round #64 1001
  9. my27_OGG MySQL To MySQL错误汇总
  10. py---------面向对象进阶