8.5.6 析构函数

    构造函数在创建对象时被系统调用,而析构函数在撤销对象时被自动调用,相比构造函数,析构函数要简单得多。析构函数有如下特点。

    ❑与类同名,之前冠以波浪号,以区别于构造函数。

    ❑析构函数没有返回类型,也不能指定参数,因此,析构函数只能有一个,不能被重载。

    ❑对象超出其作用域被销毁时,析构函数会被自动调用。与构造函数不同的是,程序员可根据需要显式调用析构函数,以撤销对象,释放对象所占据的内存空间。

    如果用户没有显式地定义构造函数,编译器将为类生成“默认析构函数”,默认析构函数是个空的函数体,只清除类的数据成员所占据的空间,但对类的函数成员通过new和malloc动态申请的内存无能为力,因此,对于动态申请的内存,应在类的析构函数中通过delete或free进行释放,这样能有效避免对象撤销造成的内存泄露,见代码8.8。

    代码8.8 用析构函数实现对象动态内存的释放Destructor


    <—————————————-文件名:computer.h———————————————-> 01 #include<iostream> 02 #include<cstring> 03 using namespace std; 04 class computer 05 { 06 private: 07 char*brand;//指针成员 08 float price; 09 public: 10 computer(const char*sz,float p) 11 { 12 brand=new char[strlen(sz)+1];//对象创建时为brand分配动态内存 13 strcpy(brand,sz);//字符串复制 14 price=p; 15 } 16 ~computer() 17 { 18 delete[]brand;//对象撤销时,释放内存,避免泄露 19 cout<<"清理现场"<<endl; 20 } 21 void print()//信息输出 22 { 23 cout<<"品牌:"<<brand<<endl; 24 cout<<"价格:"<<price<<endl; 25 } 26 }; <————————————文件名:example808.cpp———————————————> 27 #include"computer.h" 28 int main() 29 { 30 computer comp("Dell",7000);//调用构造函数声明computer变量 31 comp. print();//信息输出 32 return 0; 33 }

    输出结果如下所示。


    品牌:Dell 价格:7000 清理现场

    【代码解析】computer类的数据成员brand是字符型指针,在创建computer对象时,虽然该指针变量的内存被分配,但该指针指向的内存单元并没有分配,换句话说,该指针并没有被合法初始化,所以,在代码第12行构造函数中采用了“brand=new char[strlen(sz)+1];”为该指针初始化,开辟了一块动态内存用以复制字符串sz。

    内存空间的大小之所以是“strlen(sz)+1”,是因为C风格字符串处理函数strlen返回的长度是字符串的实际字符数,并不包括结尾的'\0',因此,需要动态申请的内存个数应做加1处理。

    本例中,在main()函数执行完毕后,computer类对象comp被撤销,系统自动调用其析构函数,输出提示信息“清理现场”,并释放析构函数中动态申请的内存。

    注意

    析构函数在对象销毁前被自动调用,对象何时销毁取决于其生存期。例如,全局对象是在程序运行结束时销毁,自动对象是在离开其作用域时销毁,而动态对象则是在使用delete运算符时销毁。析构函数的调用顺序与构造函数的调用顺序相反。