博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++虚函数表
阅读量:5159 次
发布时间:2019-06-13

本文共 2775 字,大约阅读时间需要 9 分钟。

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

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

 

#include 
using namespace std;class Base{public: virtual void fun1(){cout<<"Base::fun1\n";} virtual void fun2(){cout<<"Base::fun2\n";} virtual void fun3(){cout<<"Base::fun3\n";}private: int num1; int num2;};typedef void (*Fun)(void);int main(){ Base b; Fun pFun; //通过指针分别调用了对象b的3个虚函数。 pFun = (Fun)* ( (int*)*(int*)(&b)+0 ); pFun(); pFun = (Fun)* ( (int*)*(int*)(&b)+1 ); pFun(); pFun = (Fun)* ( (int*)*(int*)(&b)+2 ); pFun(); return 0;}/*程序执行结果如下:Base::fun1Base::fun2Base::fun3Press
to close this window...*/

程序中的Base对象b内存结构如下:


一个类会有多少张虚函数表呢?

对于一个单继承的类,如果它有虚函数,则只有一张虚函数表。对于多重继承的类,它可能有多张虚函数的表。

#include 
using namespace std;class Base1{public: Base1(int num):num_1(num){} virtual void fun1(){cout<<"Base1::fun1 "<
<
fun1(); cout<<"----- Generally inherited from Base1, covering fun2---\n"; Derived2 d2(2); pBase1 = &d2; pBase1->fun2(); cout<<"----- Multiple inheritance, no cover-----------------\n"; Derived3 d3(1,2,3); pBase1 = &d3; pBase2 = &d3; pBase3 = &d3; pBase1->fun1(); pBase2->fun1(); pBase3->fun1(); cout<<"----- Multiple inheritance, covering fun1-------------\n"; Derived4 d4(1,2,3); pBase1 = &d4; pBase2 = &d4; pBase3 = &d4; pBase1->fun1(); pBase2->fun1(); pBase3->fun1(); return 0;}/* * 程序运行结果如下:----- Generally inherited from Base1, no cover------Base1::fun1 1----- Generally inherited from Base1, covering fun2---Derived2::fun2----- Multiple inheritance, no cover-----------------Base1::fun1 1Base2::fun1 2Base3::fun1 3----- Multiple inheritance, covering fun1-------------Derived4::fun1Derived4::fun1Derived4::fun1Press
to close this window...*/

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

Derived1类继承自Base1类,没有任何覆盖基类的函数,因此Dervied1的两个虚拟函数被依次添加到了虚函数表的尾部。Derived1的虚函数表如下图:


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

Derived2继承自Base1类,并对基类中的fun2()进行了覆盖。所以虚函数表中的Derived2::fun2代替了Base::fun2,用时派生类中新的虚函数添加到虚函数的表尾。Derived2的虚函数表如下图:


多重继承(无虚函数覆盖)

Derived3继承自Base1,Base2,Base3,其虚函数表如下:

Derived3的每个父类都有自己的虚表,所以Derived3也就有了3个虚表。这里父类虚表的顺序与声明继承父类的顺序一致。这样做就是为了解决不同的父类类型的指针指向同一个子类实例,而能够调用到实际的函数。例如:

Base2 *pBase2 = new Derived3();pBase->fun2();

把Base2类型的指针指向Derived3实例,那么调用将是对应Base2虚表里的那些函数.


多重继承(有虚函数覆盖)

Derived4类继承自Base1,Base2,Base3并对3个基类的fun1函数进行了覆盖。其虚函数表如下:

可以看见基类中的fun1都被替换成了Derived4::fun1,这样,我们就可以把任意一个静态类型的父类指向子类,并调用子类的f()了。

Base1 *pBase1 = new Derived4();pBase1->fun1();

转载于:https://www.cnblogs.com/zi-xing/p/4443337.html

你可能感兴趣的文章
Python 管理 MySQL
查看>>
JDK6、Oracle11g、Weblogic10 For Linux64Bit安装部署说明
查看>>
NYOJ 488 素数环
查看>>
地址请求Eclipse中TCPIPMonitor的用法
查看>>
加班生活程序人生之我们的故事:十年如歌(5)
查看>>
Could not delete from specified tables.问题的解决方案
查看>>
使用es6 let特性做一个倒计时页面
查看>>
C++宏定义详解
查看>>
MySQL · 引擎特性 · InnoDB 事务子系统介绍
查看>>
mysql 易错误理解
查看>>
MOS文章翻译
查看>>
Part6 数组、指针与字符串 6.13字符串
查看>>
CSS3伸缩布局Flex学习笔记
查看>>
Python(67)_写函数,判断用户传入的对象(str,列表,元组)的每一个元素是否有为空,并返回...
查看>>
C语言基础课程 第三课 ADB(Android Debug Bridge)的使用
查看>>
C/C++程序员面试大纲
查看>>
物联网能否落地?可裁剪嵌入式OS成关键
查看>>
第一阶段冲刺09
查看>>
深入理解Java中的final关键字
查看>>
在JavaScript中引用类型和值类型的区别
查看>>