【C++】类和对象(4)--析构函数

一 概念

通过前面构造函数的学习,我们知道一个对象是怎么来的,那一个对象又是怎么没呢的?

析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作(Destroy).

二 特性

析构函数是特殊的成员函数,其特征如下:

1. 析构函数名是在类名前加上字符 ~

class A
{
public:
    A(int value)//构造函数
    {
        i = value;
    }
    ~A()//析构函数   
    {
        
    }
private:
    int i;
};

2. 无参数无返回值类型。

3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构

函数不能重载

class C
{
public:
	~C() { }
	~C(int i) { }    // error C2524: “C”: 析构函数 必须有“void”参数列表
	// warning C4523: “C”: 指定了多个析构函数
};

4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。

析构函数的作用并不是删除对象,而是在撤销对象占用的内存之前完成一些清理工作。

内置成员不做处理

自定义成员自动调用它的析构函数

class Stack
{
public:
       Stack(size_t capacity = 3)
       {
              cout << "Stack(size_t capacity = 3)" << endl;

              _a = (int*)malloc(sizeof(int) * capacity);
              if (nullptr == _a)
              {
                      perror("malloc申请空间失败!!!");
              }

              _capacity = capacity;
              _top = 0;
       }

       ~Stack()//析构函数
       {
              cout << "~Stack()" << endl;

              free(_a);
              _capacity = _top = 0;
              _a = nullptr;
       }

private:
       int* _a;
       int _capacity;
       int _top;
};

class MyQueue
{
       // 默认生成析构函数,行为跟构造类似
       // 内置类型成员不做处理
       // 自定义类型成员会去调用他的析构
private:
       Stack _pushst;
       Stack _popst;
       int _size = 1;
};

int main()
{
       //Stack st1;
       MyQueue mq;

       return 0;
}

如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如 Date类;有资源申请时,一定要写,否则会造成资源泄漏,比如Stack类。 

5 构造顺序是按照语句的顺序进行构造,析构是按照构造的相反顺序进行析构

构造函数用于对对象中的变量赋初值,析构函数用于释放所定义的对象的所有内存空间。构造函数和析构函数都不需要用户调用的,构造函数在定义对象时自动调用,析构函数当对象的生存期结束的时候会自动的调用。一般来说,析构函数的调用顺序与构造函数相反。但对象存储类型可以改变析构函数的调用顺序。
全局范围中定义的对象的构造函数在文件中的任何其他函数(包括main)执行之前调用(但不同文件之间全局对象构造函数的执行顺序是不确定的)。全局变量是需要在进入main()函数前即初始化的,所以在一个程序中一个全局变量的构造函数应该是第一个被调用的,比main()函数都要早同时全局对象又必须在main()函数返回后才被销毁,当main终止或调用exit函数时调用相应的析构函数,所以它的析构函数是最后才被调用。
当程序执行到对象定义时,调用自动局部对象的构造函数。该对象的析构函数在对象离开范围时调用(即离开定义对象的块时)。自动对象的构造函数与析构函数在每次对象进人和离开范围时调用。
static局部对象的构造函数只在程序执行首次到达对象定义时调用一次,对应的析构函数在main终止或调用exit函数时调用。

class A
{
public:
    A(int value)
    {
        i = value;
        cout << "Object " << i << " constructor";
    }
    ~A()    // destructor
    {
        cout << "Object " << i << " destructor" << endl;
    }
private:
    int i;
};

A first(1);  // global object全局变量

void func()
{
    A fifth(5);
    cout << " (local automatic in create)" << endl;
    static A sixth(6);
    cout << " (local static in create)" << endl;
    A seventh(7);
    cout << " (local automatic in create)" << endl;
}
int main()
{
    cout << " (global created before main)" << endl;

    A second(2);
    cout << " (local automatic in main)" << endl;

    static A third(3);  // local object
    cout << " (local static in main)" << endl;

    func();     // call function to create objects
    A fourth(4);      // local object
    cout << " (local automatic in main)" << endl;
    return 0;
}

 下面总结下不同存储类型构造函数和析构函数的调用。

构造函数的调用:
(1)全局变量:程序运行前;
(2)函数中静态变量:函数开始前;
(3)函数参数:函数开始前;
(4)函数返回值:函数返回前;
析构函数的调用:
(1)全局变量:程序结束前;
(2)main中变量:main结束前;
(3)函数中静态变量:程序结束前;
(4)函数参数:函数结束前;
(5)函数中变量:函数结束前;
(6)函数返回值:函数返回值被使用后;

 对于相同作用域和存储类别的对象,调用析构函数的次序正好与调用构造函数的次序相反

本节内容相对简单, 但是和构造函数有一定联系, 对构造函数基础不太好的可以去我博客【C++】类和对象(2)--构造函数-优快云博客

【C++】类和对象(3)--初始化列表(再谈构造函数)-优快云博客

继续加油!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值