C++析构函数

在创建对象的时候系统会自动调用构造函数,在对象需要被销毁的时候同样系统会自动调用一个函数,这个函数被称之为析构函数

析构函数就是用于回收创建对象时所消耗的各种资源。与构造函数类似,析构函数也是一个成员函数。析构函数与普通成员函数相比,有如下特征:
  • 无返回值;
  • 没有参数,不能被重载,因此一个类也只能含有一个析构函数;
  • 函数名必须为“~类名”的形式,符号“~”与类名之间可以有空格。

在上一节的 Array 类中,我们没有在类中声明析构函数,在此,我们将其补全如下。

【例 1】
#include<iostream>
using namespace std;

class Array
{
public:
    Array(){length = 0; num = NULL;};
    Array(int * A, int n);
    Array(Array &a);
    void setnum(int value, int index);
    int * getaddress();
    void display();
    int getlength(){return length;}
    ~Array();
private:
    int length;
    int * num;
};

Array::~Array()
{
    if(num != NULL)
        delete[] num;
    cout<<"destructor"<<endl;
}

Array::Array(Array & a)
{
    if(a.num != NULL)
    {
        length = a.length;
        num = new int[length];
        for(int i=0; i<length; i++)
            num[i] = a.num[i];
    }
    else
    {
        length = 0;
        num = 0;
    }  
}

Array::Array(int *A, int n)
{
    num = new int[n];
    length = n;
    for(int i=0; i<n; i++)
        num[i] = A[i];
}

void Array::setnum(int value, int index)
{
    if(index < length)
        num[index] = value;
    else
        cout<<"index out of range!"<<endl;
}

void Array::display()
{
    for(int i=0; i<length; i++)
        cout<<num[i]<<" ";
    cout<<endl;
}

int * Array::getaddress()
{
    return num;
}

int main()
{
    int A[5] = {1,2,3,4,5};
    Array arr1(A, 5);
    arr1.display();
    Array arr2(arr1);
    arr2.display();
    arr2.setnum(8,2);
    arr1.display();
    arr2.display();
    cout<<arr1.getaddress()<<" "<<arr2.getaddress()<<endl;
    return 0;
}
这是一个完整的例子,我们为其增添了一个析构函数 ~Array,该函数在 main() 函数退出前被系统自动调用,用于释放 num 所指向的内存空间。因为有两个对象,因此最终析构函数被调用了两次。

说到析构函数,则其调用顺序则不得不介绍一下了。析构函数与构造函数调用顺序是反转过来的,先调用构造函数的后调用构造函数。我们通过下面的例子来加以说明。

【例 2】
#include<iostream>
using namespace std;

class test
{
public:
    test(int i){num = i;cout<<num<<" Constructor"<<endl;}
    ~test(){cout<<num<<" Destructor"<<endl;}
private:
    int num;
};

int main()
{
    test t0(0);
    test t1(1);
    test t2(2);
    test t3(3);
    return 0;
}
程序运行结果:

0  Constructor
1  Constructor
2  Constructor
3  Constructor
3  Destructor
2  Destructor
1  Destructor
0  Destructor

从这个程序运行不难看出,析构函数的调用顺序与构造函数调用顺序正好是相反的,为了方便记忆,我们可以将之理解为一个栈,先入后出。

类的构造函数负责对象完成初始化及其它相关操作,而析构函数则用于销毁对象时完成相应的资源释放工作。在设计类过程中,我们建议为每个带有成员变量的类设计一个默认构造函数,其它构造函数及析构函数则可以视情况再定。