C++ ---- 析构函数

析构函数(distructor)是一种特殊的成员函数,与构造函数相反,名字在类名前面加一个“~”符号。对象生命周期结束时,会自动执行析构函数。有如下情况:

<1> 如果在一个函数中定义一个对象,当这个函数被调用结束时,对象应该释放,在对象释放前自动执行析构函数。

<2> static局部对象在函数调用结束时,对象并不释放,因此也不调用析构函数,只在main函数结束或者exit函数结束程序时,才调用static局部对象的析构函数。

<3> 如果定义了一个全局对象,则在程序的流程离开作用域时,才调用该对象的析构函数。

<4> 如果用new运算符动态的建立一个对象,当用delete运算符释放该对象时,先调用对象的析构函数。

析构函数的作用,并不是删除对象,而是在撤销对象占用的内存之前完成一些清理工作,使这部分内存可以被程序分配给新对象使用。析构函数不返回任何值,没有函数类型,也没有函数参数。由于没有函数参数,所以不能被重载,一个类可以有多个构造函数,但只能用一个析构函数。

实际上,析构函数的作用并不仅限于释放资源方面,它还可以被用来执行“用户希望在最后一次使用对象之后所执行的任何操作”,例如输出有关信息。

析构函数,是在声明类的时候定义的。也就是说可以完成类的设计者所指定的任何操作。一般情况下,类的设计者应当声明类的同时定义析构函数,指定“清理工作”。如果没有显性定义的话,那么编译系统会自动生成一个析构函数,但它徒有析构函数的名称和形式,不执行任何操作。

#include <string>
#include <iostream>
using namespace std;
class Student
{
public:
    Student(int n, string nam, char s)     //constructor
    {
        num = n;
        name = nam;
        sex = s;
        cout << "Constructor called." << endl;
    }
    ~Student()                             //destructor
    {
        cout << "Destructor called" << endl;
    }
   void display()
    {
        cout << "num: " << num << endl;
        cout << "name: " << name << endl;
        cout << "sex: " << sex << endl <<endl;

    }
private:                    //private data members, unaccessable to public
    int num;
    string name;
    char sex;
};


int main()
{
    Student stud1(10010, "Wang_li",'f');
    stud1.display();
    Student stud2(10011, "Zhang_fun",'m');
    stud2.display();
    return 0;
}

在main函数前面声明类,它的作用域是全局的。这样可以使main函数更加简练。在student类中定义了构造函数和析构函数。在执行main函数时先建立对象stud1,同时调用构造函数,给该对象中的数据成员赋初值,然后执行dispaly函数。同样的执行对象stud2。在执行return语句后,主函数的语句已经执行完毕,对主函数的调用结束了。在主函数中建立对象是局部的,生命周期随着主函数的结束而结束,在撤销对象之前的最后一项工作是调用析构函数。这里的析构函数并无实质作用,只是输出一个信息。

Constructor called.
num = 10010
name = Wang_li
sex = f
Constructor called.
num = 10011
name = Zhang_fun
sex = m
Destructor called
Destructor called
Program ended with exit code: 0

细心的人会发现,为什么会有两个“Destructor called”的?这个不难解释,因为main函数中定义了两个对象。那么进一步思考,这两个的顺序是怎么样的?哪个是stud1哪个是stud2?

这里有一个顺序:“先构造的后析构,后构造的先析构”。

验证一下:在Student类的析构函数改写成:

cout << "Destructor called" << num <<endl;

输出结果为:

Constructor called.
num = 10010
name = Wang_li
sex = f
Constructor called.
num = 10011
name = Zhang_fun
sex = m
Destructor called 10011
Destructor called 10010
Program ended with exit code: 0

验证了“先构造的后析构,后构造的先析构”。有个前提,这是对同一类存储的对象而言。但是并不都是按照这个原则处理的。作用域和存储类别会对这个处理原则产生影响的。例如:如果在函数中定义静态(static)局部对象,则只在程序第一次调用此函数时调用一次构造函数,在调用结束时,对象并不释放,因此也不会调用析构函数,只在main函数结束或者调用exit函数结束程序时,才调用析构函数。

void fn()
{
   Student stud1;                                   //定义自动局部对象
   static Student stud2;                            //定义静态对象
        .
        .
        .
}
在调用fn函数时,先调用stud1的构造函数,在调用stud2的构造函数,在fn调用结束时,stud1是要释放的(因为它是自动局部对象),因此调用析构函数。而stud2是静态局部对象,在fn调用结束时并不释放,因此不调用析构函数。直到程序结束释放stud12,才会调用析构函数。


猜你喜欢

转载自blog.csdn.net/nearcsy/article/details/80954708