学科分类
目录
C++基础

析构函数

前面介绍的构造函数用于在创建对象时完成数据成员的初始化,与之对应,对象生命期结束前应该完成对象资源的清理,这个工作由析构函数完成。比如创建对象时为数据成员开辟的空间,会通过析构函数在对象的生命期结束前进行释放。

析构函数是类中特殊的成员函数,用于完成资源清理,析构函数的定义形式如下所示:

类名::~析构函数()
{
  函数体
}

定义析构函数应满足以下要求:

● 析构函数的名称是在构造函数名称之前添加“~”。

● 析构函数没有参数。

● 析构函数中不能通过return语句返回一个值。

● 一个类中只能有一个析构函数,不可重载。

下面在类Car中添加析构函数,代码如下所示:

class Car
{
public:
    Car()                   //构造函数
    {
    ​    m_strCarName = "car name";
    ​     m_nSeats = 4;
      }
       ~Car()                   //析构函数
      {
      }
private:
      string m_strCarName;
      int m_nSeats;
};

上述代码中的析构函数没有做任何工作。与构造函数类似,若类中没有显式定义析构函数,则编译器会给出一个默认的析构函数,该函数没有具体的动作,在对象生命期结束时默认的析构函数被执行。

接下来通过一个案例来说明如何通过析构函数释放对象资源,如例1所示。

例1

 1    #include <iostream>
 2    #include <cstring>                                     //strcpy_s()函数声明所在的头文件
 3    using namespace std;
 4    
 5    class Car                                               //定义类
 6    {
 7    public:
 8        Car();                                             //无参构造函数的声明
 9        Car(char *con_pcarname, int con_seats);     //带参构造函数的声明
 10        ~Car();                                            //析构函数的声明
 11        char *get_carname();
 12        int get_seats();
 13    private:
 14        char *m_pCarName;
 15        int m_nSeats;
 16    };
 17    Car::Car()                                           //定义无参的构造函数
 18    {
 19        cout << "Car constructor!" << endl;
 20        m_pCarName = nullptr;                        //设置指针成员的初值为nullptr,值为0
 21        m_nSeats = 4;
 22    }
 23    Car::Car(char *con_pcarname, int con_seats)  //定义带参数的构造函数
 24    {
 25        int len = strlen(con_pcarname) + 1;
 26    
 27        cout << "Car constructor with param,car name:" << con_pcarname <<endl;
 28        m_pCarName = new char[len];                //数据成员m_pCarName指向新开辟的空间
 29        strcpy_s(m_pCarName, len, con_pcarname); //将汽车名车存入m_pCarName指向的空间
 30        m_nSeats = con_seats;
 31    }
 32    Car::~Car()                                        //定义析构函数
 33    {
 34        static int i = 0;
 35        cout << "Car destructor,car name:" << m_pCarName << endl;
 36        if (m_pCarName)
 37            delete[] m_pCarName;                    //释放m_pCarName指向的空间
 38        if (i == 1)
 39            system("pause");
 40        i++;
 41    }
 42    char *Car::get_carname()                        //获取m_pCarName属性值
 43    {
 44        return m_pCarName;
 45    }
 46    int Car::get_seats()                             //获取m_nSeats属性值
 47    {
 48        return m_nSeats;
 49    }
 50    int main()
 51    {
 52        Car mynewcar("my car", 4);             //创建对象
 53        Car tomcar("tom car", 7);              //创建对象
 54    
 55        cout << "my car name : " << mynewcar.get_carname() << endl;
 56        cout << "tom car name: " << tomcar.get_carname() << endl;
 57        
 58        return 0;
 59    }

运行结果如图1所示。

图1 例2-10运行结果

例1中类Car内定义了指针数据成员m_pCarName,用来记录存有汽车名称空间的地址,通过构造函数Car(char *con_pcarname, int con_seats)对m_pCarName进行初始化时,应通过new开辟一段空间存放汽车名称,空间地址记录在m_pCarName中。m_pCarName与存放汽车名称空间的关系如图2所示。

图2 m_pCarName指向开辟的空间

例1构造函数中会通过new开辟空间,new应该与delete严格匹配,因此在对象的生命期结束前应该通过delete释放空间,析构函数能够完成这样的工作。代码32-41行是析构函数,第36行测试m_pCarName指针是否有效,若有效则代表m_pCarName指向一段new的空间,应通过delete释放。从运行结果看出,对象生命期结束时析构函数被自动调用,完成了资源清理工作。

另外,运行结果还显示,若定义了多个类对象:mynewcar、tomcar,析构函数的调用顺序和构造函数的调用顺序相反,后创建的对象先析构,先创建的对象后析构。

点击此处
隐藏目录