C++ 虚函数列表(虚函数表,vtable)
虚函数列表(通常称为虚函数表或vtable)是C++实现运行时多态(动态绑定)的关键机制。下面详细介绍虚函数表的相关内容:
1. 虚函数表的基本概念
- 虚函数表(vtable):每个包含虚函数的类都有一个虚函数表,表中存储了该类所有虚函数的地址
- 虚指针(vptr):每个对象内部有一个隐藏的指针指向该类的虚函数表
- 动态绑定:通过虚函数表在运行时确定调用哪个函数实现
2. 虚函数表的结构
对于这样一个类层次结构:
class Base { public: virtual void func1() {} virtual void func2() {} }; class Derived : public Base { public: void func1() override {} virtual void func3() {} };
虚函数表大致如下:
Base类的vtable:
[0] Base::func1() 的地址 [1] Base::func2() 的地址
Derived类的vtable:
[0] Derived::func1() 的地址 // 覆盖了Base的func1 [1] Base::func2() 的地址 // 继承自Base [2] Derived::func3() 的地址 // 新增虚函数
3. 虚函数表的工作原理
Base* ptr = new Derived(); ptr->func1(); // 实际调用Derived::func1()
调用过程:
- 通过对象的vptr找到vtable
- 在vtable中找到func1对应的条目
- 跳转到该地址执行
4. 虚函数表的特点
- 每个类一个vtable:不是每个对象一个,同类的对象共享同一个vtable
- 编译时创建:虚函数表在编译时生成,存放在程序的只读数据段
- 继承关系: 派生类继承基类的vtable覆盖的虚函数会替换对应位置的函数指针新增的虚函数会追加到vtable末尾
5. 虚函数表的开销
- 空间开销:每个包含虚函数的类有一个vtable每个对象多一个vptr(通常4或8字节)
- 时间开销:虚函数调用需要间接寻址(多一次指针解引用)通常无法内联虚函数
6. 查看虚函数表的方法(GCC)
可以使用-fdump-class-hierarchy
选项查看虚函数表布局:
g++ -fdump-class-hierarchy your_file.cpp
7. 虚函数表的实际应用
- 动态多态的基础
- **RTTI(运行时类型识别)**的实现依赖虚函数表
- dynamic_cast的实现也依赖虚函数表
8. 注意事项
- 构造函数不能是虚函数(因为此时vptr尚未初始化)
- 析构函数通常应该是虚函数(特别是基类)
- 虚函数表机制是编译器实现的,C++标准只规定行为,不规定实现方式
虚函数表是理解C++多态底层机制的关键,了解它有助于编写更高效的C++代码和调试复杂的继承问题。