C++析构函数详解
C++ 提供了一系列用于资源管理和对象生命周期控制的机制,其中析构函数(Destructor)就是一个重要的部分。
在 C++ 中,创建对象的时候会调用构造函数,相应地在释放对象的时候会调用析构函数。同构造函数一样,析构函数也是类中一个特殊的成员函数,并且也是由编译器自动调用的。
虽然很多初学者可能觉得析构函数不常用,但了解其工作原理与应用场景是深入理解 C++ 的关键。本节重点介绍析构函数的定义和使用。
析构函数通常用来做“清理善后”的工作,例如在建立对象时用 new 开辟了一片内存空间,对象被销毁时应手动用 delete 释放,释放的工作就可以放在析构函数里。
析构函数的名称和类名相同,但前面加有波浪号
例如:
使用析构函数时,还需要注意以下两点:
在 C++ 中,创建对象的时候会调用构造函数,相应地在释放对象的时候会调用析构函数。同构造函数一样,析构函数也是类中一个特殊的成员函数,并且也是由编译器自动调用的。
虽然很多初学者可能觉得析构函数不常用,但了解其工作原理与应用场景是深入理解 C++ 的关键。本节重点介绍析构函数的定义和使用。
析构函数的定义
和构造函数相反,当类对象脱离它的作用域时(例如对象所在的函数已调用完毕),编译器会自动执行析构函数。析构函数通常用来做“清理善后”的工作,例如在建立对象时用 new 开辟了一片内存空间,对象被销毁时应手动用 delete 释放,释放的工作就可以放在析构函数里。
析构函数的名称和类名相同,但前面加有波浪号
~
。与构造函数相反,析构函数没有参数,也不能被重载。例如:
class MyClass { public: // 构造函数 MyClass() { // 分配资源 } // 析构函数 ~MyClass() { // 释放资源 } };如果不在类中手动定义析构函数,那么编译器也会自动添加一个析构函数,不过这个由编译器添加的析构函数不进行任何操作。因此,如果有一些需要自己去释放的东西,比如释放堆空间、关闭文件句柄等,就一定要手动定义析构函数。
使用析构函数时,还需要注意以下两点:
- 如果一个类有基类或成员对象,其析构函数会自动调用基类和成员对象的析构函数。
- 析构函数应该是虚函数,特别是在基类中,以支持多态。
完整实例
下面的实例演示了一个名为 Person 的简单类,该类动态分配一个字符数组来存储名字,并在析构函数中释放这个数组。#include <iostream> #include <cstring> class Person { public: // 构造函数 Person(const char* name) { this->name = new char[strlen(name) + 1]; strcpy(this->name, name); std::cout << name << " is born!" << std::endl; } // 析构函数 ~Person() { std::cout << name << " is gone!" << std::endl; delete[] name; } private: char* name; }; int main() { { Person p1("Alice"); Person p2("Bob"); } // p1 和 p2 的析构函数在这里调用 Person* p3 = new Person("Charlie"); delete p3; // p3 的析构函数在这里调用 return 0; }输出结果为:
Alice is born!
Bob is born!
Bob is gone!
Alice is gone!
Charlie is born!
Charlie is gone!