C++中的虚函数和虚函数表
虚函数和虚函数表
动态多态: 在程序运行时根据对象的实际类型确定调用哪个类的成员函数
C++是如何实现动态多态的?
通过虚函数实现的,为每一个包含虚函数的对象分配一个虚函数指针,这个虚函数指针指向一个放在常量区的虚函数表。在运行时运行到某个虚函数时,根据这个虚函数指针来找到对应的虚函数表,然后根据对应的这个函数的下标值在虚函数表中找到对应的虚函数来完成调用。
示例:
1 |
|
内存布局相关:
一个类多重继承了几个父类,就有几张虚函数表。一个类有几个虚函数表,一个类的对象就有几个虚函数指针。虚函数指针按照继承父类的顺序,从对象的首地址开始依次排布。
- 单继承中:父类的虚函数在子类虚函数前面,按照声明顺序排序,共同形成一张表,如果子类有和父类相同的虚函数,会对父类的虚函数进行覆盖。
- 多继承中:子类和第一个继承的父类形成一张表,剩下的父类单独形成一个虚函数表,同样的,如果子类有和父类相同的虚函数,会对父类的虚函数进行覆盖。
析构函数为什么要是虚函数?
由于基类的多态性,基类指针可以指向派生类对象,如果删除该基类指针,就会调用该指针指向的派生类析构函数,然后派生类析构函数又自动调用积累的析构函数,这样整个派生类对象就会被完全释放。
如果析构函数不被声明为虚函数,删除基类指针时只会调用基类的析构函数而不会调用派生类析构函数。
构造函数可以是虚函数吗?
不可以
- 如果构造函数是虚函数,就需要通过虚函数表中对应的虚函数指针来调用,可是对象如果还没有实例化,也就没有内存空间,就没有虚函数指针了。
- 构造函数是自动调用的,不用通过父类的指针或者引用去调用,不需要将其设置为虚函数
虚函数和普通函数之间的区别:
主要体现在多态的支持和调用方式上,虚函数是实现运行时多态(动态绑定)的核心机制
- 绑定方式:
- 虚函数:采用动态绑定,调用哪个函数由对象的实际类型决定。
- 普通函数:采用静态绑定,函数的调用在编译时就已经确定,不依赖于运行时的对象类型。
- 性能差异:
- 虚函数:调用比普通函数蛮,因为它需要通过虚表进行动态查找
- 普通函数:直接调用,不需要通过虚表,因此速度较快
- 内存开销:
- 虚函数:需要为每个对象增加一个虚函数表指针,该指针指向虚函数表,这个虚表包含了该类的虚函数的地址。增加了内存开销
- 普通函数:没有虚表,没有额外内存开销
计算这个类的大小:
1 |
|
- int a通常占4个字节
- char c通常占1个字节,但是有3个填充字节为了对齐虚表指针
- 虚表指针在64位系统中为8字节,在32位系统中为4字节
所以32位系统为12字节,64位系统为16字节
C++中的虚函数和虚函数表
http://example.com/2024/12/22/C-中的虚函数和虚函数表/