当前课程知识点:C++语言程序设计进阶 > 第八章 多态性 > 虚函数 > 虚表与动态绑定
虚表
每个多态类有一个虚表(virtual table)
虚表中有当前类的各个虚函数的入口地址
每个对象有一个指向当前类的虚表的指针(虚指针vptr)
动态绑定的实现
构造函数中为对象的虚指针赋值
通过多态类型的指针或引用调用成员函数时,通过虚指针找到虚表,进而找到所调用的虚函数的入口地址
通过该入口地址调用虚函数
大家好
欢迎回来继续学习
C++语言程序设计
现在我们看到了
虚函数确实是一个很好的东西
可以实现运行时的动态绑定
实现多态性
使得程序更加灵活了
使得我们对整个类家族的
不同的基类派生类
它们的对象
可以用同样的方式
进行统一处理
确实是很好的一种机制
但是
大家有没有问一个为什么呢
到底在运行的时候
它为什么可以实现动态绑定
运行的时候没有编译环境了
只有一个操作系统
我们把可执行程序
放在操作系统上运行
这个时候
谁帮我们去确定
该执行哪个函数体呢
其实还是编译器
为我们预先做好了准备
在编译的时候
就埋下伏笔了
做好准备了
这就是虚表
那么每个多态的类呢
它都有一个虚表
这个虚表里面有当前
类的各个虚函数的入口地址
每个具有虚表的类
也就是具有多态性的类
它的对象都隐含有一个
指向当前类的虚表的指针
那么动态绑定呢
就是通过这样的虚表来实现的
现在我们来看一下
这个虚表的示意图
我们举一个简单的例子
比如说有一个Base类
它里面有虚函f g
然后呢
它的派生类Derived类
有虚函数f h
那么在编译阶段
这两个类都有虚函数
于是呢
编译器就得为动态绑定
做好准备
这是Base类的虚表
因为它有虚函数
所以
编译器在编译的时候
就会为它去生成一个虚表
Derived类也有虚函数
所以编译器
也为它生成一个虚表
Base类
它的虚表里面
有指向函数f
和函数g的指针
这都是它自己本类定义的函数
那么Derived类
一共有哪些虚函数呢
有自己定义的函数f 函数h
还有从它的基类
继承过来的这个函数g
它们都是虚函数
所以都要放在虚表里面
函数f 函数h的指针呢
会指向自己定义的虚函数
因为派生类中定义的这个函数f
覆盖了基类
继承过来的虚函数f
所以它指向自己的
函数h是派生类自己新增的
这个虚函数
而派生类中并没有定义
同名的同原型的函数g
所以呢
它的g函数的指针
就指向了
基类里面的这个虚函数g
然后呢
对于Base类的对象
和Derived的对象呢
每一个具有虚表的这个类
它的对象里面
都隐含了一个指向虚表的指针
所以这个时候它的对象
所占据的空间
它所存储的数据
就不仅仅是
我们显示定义的这个成员i
成员j
这个Derived成员的新增的一个j
还有从Base类继承了一个i
这是我们清楚地意识到的
这是我们自己定义的数据成员
但是隐含着
除此之外还有一个指针
每个具有虚表的类
它的对象
都含有一个隐含的指针
指向它的虚表
所以我们才可以实现动态绑定
在运行时
如果有一个指针指向了对象
是派生类自己的指针也好
是基类的指针也好
当要通过这个指针
去调用一个函数的时候
首先都会通过这个指针
找到对象里面的这个虚表指针
然后找到虚表
从虚表里找到指向函数的指针
去调用相应的函数体
所以才可以在运行时
根据指针所指向的对象
去正确地调用这个对象
它自己的功能函数
这就是一个简单的动态绑定的
这种虚表示意图
-导学
--导学
-继承的基本概念和语法
-第七章 继承与派生--继承的基本概念和语法习题
-继承方式
-第七章 继承与派生--继承方式
-基类与派生类类型转换
-第七章 继承与派生--基类与派生类类型转换
-派生类的构造和析构
--派生类的构造函数
--派生类的析构函数
--第七章 继承与派生--派生类的构造和析构
-派生类成员的标识与访问
--虚基类
-第七章 继承与派生--派生类成员的标识与访问
-小结
--小结
-综合实例
--第七章综合实例
-实验七
--实验七
-导学
--导学
-第八章 多态性--导学
-运算符重载
--运算符重载的规则
-第八章 多态性--运算符重载
-虚函数
--虚函数
--虚析构函数
--虚表与动态绑定
-第八章 多态性--虚函数
-抽象类
--抽象类
--第八章 多态性--抽象类
-override与final
-第八章 多态性--override与final
-小结
--第八章小结
-综合实例
--第八章综合实例
-实验八
--实验八
- 第八章讲义
-导学
--导学
-模板
--函数模板
--类模板
-第九章 模板与群体数据--模板
-线性群体
--线性群体的概念
-第九章 模板与群体数据--线性群体
-数组
--数组类模板
-链表
--链表类模板
-第九章 模板与群体数据--链表
-栈
--栈类模板
--栈类模板课后习题
--例9-9 栈的应用课后习题
-队列
--队列类模板
-第九章 模板与群体数据--队列
-排序
--排序概述
--插入排序
--选择排序
--交换排序
-第九章 模板与群体数据--排序
-查找
--查找
--查找课后习题
-小结
--小结
-综合实例
--综合实例
-实验九
--实验九
- 第九章讲义
-导学
--导学
-泛型程序设计及STL的结构
--STL简介
-第十章 泛型程序设计与C++标准模板库--泛型程序设计及STL的结构
-迭代器
--迭代器
-第十章 泛型程序设计与C++标准模板库--迭代器
-容器的基本功能与分类
-第十章 泛型程序设计与C++标准模板库--容器的基本功能与分类
-顺序容器
--顺序容器的特征
--第十章 泛型程序设计与C++标准模板库--顺序容器
-关联容器
--集合
--映射
-第十章 泛型程序设计与C++标准模板库--关联容器
-函数对象
--函数对象
--函数适配器
-算法
--算法
-小结
--第十章小结
-综合实例
--综合实例
-实验十
--实验十
- 第十章讲义
-导学
--导学
-I/O流的概念及流类库结构
-第十一章 流类库与输入/输出--I/O流的概念及流类库结构
-输出流
--输出流概述
--向文本文件输出
--向二进制文件输出
--向字符串输出
-第十一章 流类库与输入/输出--输出流
-输入流
--输入流概述
--输入流应用举例
--从字符串输入
-第十一章 流类库与输入/输出--输入流
-输入/输出流
--输入/输出流
-第十一章 流类库与输入/输出--输入/输出流
-小结
--小结
-综合实例
--综合实例
-实验十一
--实验十一
- 第十一章讲义
-导学
--第12章导学
-异常处理的思想与程序实现
-第十二章 异常处理--异常处理的思想与程序实现
-异常处理中的构造与析构
-第十二章 异常处理--异常处理中的构造与析构
-标准程序库异常处理
-第十二章 异常处理--标准程序库异常处理
-小结
--第12章小结
-综合实例
--综合实例
-实验十二
--实验十二
- 第十二章讲义