虚函数
Mzy 金丹

虚函数

什么是虚函数

虚函数是在基类中声明的,而在派生类中进行重写的函数。通过使用virtual关键字声明一个函数为虚函数,它使得在运行时能够动态地确定调用的是哪个版本的函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Base {
public:
virtual void show() {
std::cout << "Base class\n";
}
};

class Derived : public Base {
public:
void show() override {
std::cout << "Derived class\n";
}
};

虚函数的作用

  • 实现多态性(Polymorphism):允许通过基类指针或引用调用派生类对象的函数,根据实际对象的类型选择相应的函数实现。
  • 运行时绑定(Runtime Binding):虚函数通过表格(虚函数表)的方式实现,使得在运行时动态地绑定函数调用。

虚函数表(vtable)

每个含有虚函数的类都有一个虚函数表,其中存储了虚函数的地址。对象的内存布局中包含一个指向虚函数表的指针。派生类的虚函数表包含基类的虚函数表,并在适当的位置添加或替换新的虚函数地址。

纯虚函数

纯虚函数是一个在基类中声明但没有提供实现的虚函数,它通过在声明中使用= 0来标识。类含有纯虚函数的类被称为抽象类,不能被实例化。派生类必须实现纯虚函数,否则也会变为抽象类。

1
2
3
4
class AbstractBase {
public:
virtual void pureVirtualFunction() = 0;
};

虚析构函数

如果基类的析构函数是虚函数,当通过基类指针删除派生类对象时,会调用派生类的析构函数。这是为了确保正确的对象销毁。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Base {
public:
virtual ~Base() {
std::cout << "Base destructor\n";
}
};

class Derived : public Base {
public:
~Derived() override {
std::cout << "Derived destructor\n";
}
};

img

image-20240612122221519

构造函数可以是虚函数吗?析构函数呢?

C++中,构造函数不可以是虚函数,而析构函数可以且常常是虚函数。

从存储空间角度,虚函数相应一个指向vtable虚函数表的指针,但是这个指向vtable的指针事实上是存储在对象的内存空间的。假设构造函数是虚的,就须要通过 vtable来调用,但是对象没有实例化,也就是内存空间没有,找不到vtable

img

在析构函数中写delete this可以吗?在类中的其他函数中写呢?

this指针:当一个对象声明时,系统会为这个对象分配一块内存空间,this指针指向这块内存空间,这块空间里面存着对象的数据成员和虚函数表指针。

使用delete的时候:第一步,针对此内存会有一个(或更多)析构函数被调用,第二步才会释放该内存。

在成员函数中调用delete this,会导致指针错误,而在析构函数中调用delete this,出导致死循环,造成堆栈溢出。

指针大小只与操作系统位数相关,如64位机器,为8字节

哪些函数不能为虚函数?

构造函数、静态函数、友元函数、内联函数

继承

  1. 派生类对象初始化先调用基类构造再调派生类构造
  2. 派生类对象析构清理先调用派生类析构再调基类的析构

image-20240415195059387

基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有一个static成员实例

虚析构函数的作用

虚析构函数使得在删除指向子类对象的基类指针时可以调用子类的析构函数达到释放子类中堆内存的目的,而防止内存泄露的。

C++虚函数表保存在.rdata只读数据段

Powered by Hexo & Theme Keep
Unique Visitor Page View