虚函数表与虚函数表是用来实现多态的,每一个类只有一个虚函数表
静态多态:函数重载(编译期确定)
动态多态:虚函数(运行期确定)
虚函数表的创建时机:
- 生成时间:
- 编译期生成,识别到
virtual
关键字修饰的函数,虚函数地址的数组 .bss
: 未初始化的或者自动初始化为0的全局、静态变量.data
: 已经初始化的全局、静态变量.rodata
: 只读数据段,虚函数表,常量数据
- 编译期生成,识别到
- 存放在哪里: 可执行程序(磁盘,只读数据段
.rodata
), 运行状态(内存)
虚函数指针:
- 存放位置:
- 一般在类的最开始位置,4字节(32位), 8字节(64位)
- 堆区,指向虚函数表的地址
- 类的不同对象虚函数表指针不一样
- 创建时间:
- 类对象构造的时候,初始化
vptr
- 如果对象是派生类,在
vptr
随着构造函数逐层向下进行构造,每个类指向自己的虚函数表;即构造函数先分配堆或者栈的内存,然后初始化vptr
,然后初始化其他成员并执行构造函数体 - 注:
vptr
在构造期间可能多次更新。当基类构造函数运行时,vptr
指向基类虚函数表。而当派生类构造函数执行时,vptr
会更新为指向派生类的虚函数表。这保证了构造期间,任何函数的调用都将解析到当前构造阶段的正确版本。
- 类对象构造的时候,初始化
- 对象析构:
- 同理,在析构期间,从子类析构到父类,
vptr
将依次被设置会每个级别的基类。 - 这里也引出了另外一个问题,在继承结构中析构函数最好为虚函数,这样当指向派生类的基类指针这种结构出现的时候,我们进行析构,通过虚函数指针的作用可以先执行子类的析构,再执行父类的析构,防止析构子类之后找不到父类的析构函数了(这是另外一个较大的问题,这里太小写得简略一下,可以自行搜索一下)。
- 同理,在析构期间,从子类析构到父类,
最后给大家推荐一个LinuxC/C++高级架构系统教程的学习资源与课程,可以帮助你有方向、更细致地学习C/C++后端开发,具体内容请见 https://xxetb.xetslk.com/s/1o04uB