虚函数
什么是虚函数
虚函数是在基类中声明的,而在派生类中进行重写的函数。通过使用virtual
关键字声明一个函数为虚函数,它使得在运行时能够动态地确定调用的是哪个版本的函数。
1 | class Base { |
虚函数的作用
- 实现多态性(Polymorphism):允许通过基类指针或引用调用派生类对象的函数,根据实际对象的类型选择相应的函数实现。
- 运行时绑定(Runtime Binding):虚函数通过表格(虚函数表)的方式实现,使得在运行时动态地绑定函数调用。
虚函数表(vtable)
每个含有虚函数的类都有一个虚函数表,其中存储了虚函数的地址。对象的内存布局中包含一个指向虚函数表的指针。派生类的虚函数表包含基类的虚函数表,并在适当的位置添加或替换新的虚函数地址。
纯虚函数
纯虚函数是一个在基类中声明但没有提供实现的虚函数,它通过在声明中使用= 0
来标识。类含有纯虚函数的类被称为抽象类,不能被实例化。派生类必须实现纯虚函数,否则也会变为抽象类。
1 | class AbstractBase { |
虚析构函数
如果基类的析构函数是虚函数,当通过基类指针删除派生类对象时,会调用派生类的析构函数。这是为了确保正确的对象销毁。
1 | class Base { |
构造函数可以是虚函数吗?析构函数呢?
C++中,构造函数不可以是虚函数,而析构函数可以且常常是虚函数。
从存储空间角度,虚函数相应一个指向vtable虚函数表的指针,但是这个指向vtable的指针事实上是存储在对象的内存空间的。假设构造函数是虚的,就须要通过 vtable来调用,但是对象还没有实例化,也就是内存空间还没有,找不到vtable
在析构函数中写delete this可以吗?在类中的其他函数中写呢?
this指针:当一个对象声明时,系统会为这个对象分配一块内存空间,this指针指向这块内存空间,这块空间里面存着对象的数据成员和虚函数表指针。
使用delete的时候:第一步,针对此内存会有一个(或更多)析构函数被调用,第二步才会释放该内存。
在成员函数中调用delete this,会导致指针错误,而在析构函数中调用delete this,出导致死循环,造成堆栈溢出。
指针大小只与操作系统位数相关,如64位机器,为8字节
哪些函数不能为虚函数?
构造函数、静态函数、友元函数、内联函数
继承
- 派生类对象初始化先调用基类构造再调派生类构造。
- 派生类对象析构清理先调用派生类析构再调基类的析构。
⭕基类定义了static
静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有一个static
成员实例 。
虚析构函数的作用
虚析构函数使得在删除指向子类对象的基类指针时可以调用子类的析构函数达到释放子类中堆内存的目的,而防止内存泄露的。
C++虚函数表保存在.rdata只读数据段