创建对象时系统会自动调用构造函数进行初始化工作,同样,销毁对象时系统也会自动调用一个函数来进行清理工作,例如释放分配的内存、关闭打开的文件等,这个函数就是析构函数。

析构函数(Destructor)也是一种特殊的成员函数,没有返回值,不需要程序员显式调用(程序员也没法显式调用),而是在销毁对象时自动执行。构造函数的名字和类名相同,而析构函数的名字是在类名前面加一个~符号。

注意:析构函数没有参数,不能被重载,因此一个类只能有一个析构函数。如果用户没有定义,编译器会自动生成一个默认的析构函数。

上节我们定义了一个 VLA 类来模拟变长数组,它使用一个构造函数为数组分配内存,这些内存在数组被销毁后不会自动释放,所以非常有必要再添加一个析构函数,专门用来释放已经分配的内存。请看下面的完整示例:

#include <iostream>
using namespace std; class VLA{
public:
VLA(int len); //构造函数
~VLA(); //析构函数
public:
void input(); //从控制台输入数组元素
void show(); //显示数组元素
private:
int *at(int i); //获取第i个元素的指针
private:
const int m_len; //数组长度
int *m_arr; //数组指针
int *m_p; //指向数组第i个元素的指针
}; VLA::VLA(int len): m_len(len){
if(len > ){ m_arr = new int[len]; /*分配内存*/ }
else{ m_arr = NULL; }
}
VLA::~VLA(){
delete[] m_arr; //释放内存
}
void VLA::input(){
for(int i=; m_p=at(i); i++){ cin>>*at(i); }
}
void VLA::show(){
for(int i=; m_p=at(i); i++){
if(i == m_len - ){ cout<<*at(i)<<endl; }
else{ cout<<*at(i)<<", "; }
}
}
int * VLA::at(int i){
if(!m_arr || i< || i>=m_len){ return NULL; }
else{ return m_arr + i; }
} int main(){
//创建一个有n个元素的数组(对象)
int n;
cout<<"Input array length: ";
cin>>n;
VLA *parr = new VLA(n);
//输入数组元素
cout<<"Input "<<n<<" numbers: ";
parr -> input();
//输出数组元素
cout<<"Elements: ";
parr -> show();
//删除数组(对象)
delete parr; return ;
}

运行结果:
Input array length: 5
Input 5 numbers: 99 23 45 10 100
Elements: 99, 23, 45, 10, 100

~VLA()就是 VLA 类的析构函数,它的唯一作用就是在删除对象(第 53 行代码)后释放已经分配的内存。

函数名是标识符的一种,原则上标识符的命名中不允许出现~符号,在析构函数的名字中出现的~可以认为是一种特殊情况,目的是为了和构造函数的名字加以对比和区分。

注意:at() 函数只在类的内部使用,所以将它声明为 private 属性;m_len 变量不允许修改,所以用 const 限制。

C++ 中的 new 和 delete 分别用来分配和释放内存,它们与C语言中 malloc()、free() 最大的一个不同之处在于:用
new 分配内存时会调用构造函数,用 delete
释放内存时会调用析构函数。构造函数和析构函数对于类来说是不可或缺的,所以在C++中我们非常鼓励使用 new 和 delete。

析构函数的执行时机

析构函数在对象被销毁时调用,而对象的销毁时机与它所在的内存区域有关。不了解内存分区的读者请阅读《C语言和内存》专题。

在所有函数之外创建的对象是全局对象,它和全局变量类似,位于内存分区中的全局数据区,程序在结束执行时会调用这些对象的析构函数。

在函数内部创建的对象是局部对象,它和局部变量类似,位于栈区,函数执行结束时会调用这些对象的析构函数。

new 创建的对象位于堆区,通过 delete 删除时才会调用析构函数;如果没有 delete,析构函数就不会被执行。

下面的例子演示了析构函数的执行。

#include <iostream>
#include <string>
using namespace std; class Demo{
public:
Demo(string s);
~Demo();
private:
string m_s;
};
Demo::Demo(string s): m_s(s){ }
Demo::~Demo(){ cout<<m_s<<endl; } void func(){
//局部对象
Demo obj1("");
} //全局对象
Demo obj2(""); int main(){
//局部对象
Demo obj3("");
//new创建的对象
Demo *pobj4 = new Demo("");
func();
cout<<"main"<<endl; return ;
}

运行结果:
1
main
3
2

本帖原文地址:

http://c.biancheng.net/cpp/biancheng/view/196.html

【转】c++析构函数(Destructor)的更多相关文章

  1. 构造函数constructor 与析构函数destructor(五)

    我们知道当调用默认拷贝构造函数时,一个对象对另一个对象初始化时,这时的赋值时逐成员赋值.这就是浅拷贝,当成员变量有指针时,浅拷贝就会在析构函数那里出现问题.例如下面的例子: //test.h #ifn ...

  2. 构造函数constructor 与析构函数destructor(一)

    构造函数定义:构造函数c++中在创建对象时自动调用,用来初始化对象的特殊函数. (1)构造函数的名字必须与类的名字相同,不能有返回值,哪怕是void 也不行. (2)通常情况下构造函数应声明为公有函数 ...

  3. C#析构函数(destructor)和终结器(Finalizer) .

    使用析构函数释放资源 析构函数用于析构类的实例. 1)         不能在结构中定义析构函数.只能对类使用析构函数. 2)         一个类只能有一个析构函数. 3)         无法继 ...

  4. 构造函数constructor 与析构函数destructor(四)

    拷贝构造函数:拷贝构造函数就是在用一个类对象来创建另外一个类对象时被调用的构造函数,如果我们没有显示的提供拷贝构造函数,编译器会隐式的提供一个默认拷贝构造函数. 拷贝构造函数的定义是X(const X ...

  5. 构造函数constructor 与析构函数destructor(二)

    (1)转换构造函数 转换构造函数的定义:转换构造函数就是把普通的内置类型转换成类类型的构造函数,这种构造函数只有一个参数.只含有一个参数的构造函数,可以作为两种构造函数,一种是普通构造函数用于初始化对 ...

  6. 构造函数constructor 与析构函数destructor(三)

    (1)构造函数初始化列表: 1 class Test{ 2 int i; 3 public: 4 Test(int vi):i(vi){}//这里的从冒号开始,到右大括号结束,这一段是构造函数初始化列 ...

  7. 【C#】析构函数

    MSDN paper 析构函数 析构函数(destructor) 与构造函数相反,当对象脱离其作用域时(例如对象所在的函数已调用完毕),系统自动执行析构函数. 析构函数往往用来做“清理善后” 的工作( ...

  8. php部分---面向对象:定义、实例化、构造函数、析构函数;

    类 − 定义了一件事物的抽象特点.类的定义包含了数据的形式以及对数据的操作. 对象 − 是类的实例.一切皆对象.由类实例化出来的. 成员变量 − 定义在类内部的变量.该变量的值对外是不可见的,但是可以 ...

  9. 析构函数(C#)

    析构函数又称终结器,用于析构类的实例. 定义 析构函数(destructor) 与构造函数相反,当对象结束其生命周期时(例如对象所在的函数已调用完毕),系统自动执行析构函数.析构函数往往用来做&quo ...

随机推荐

  1. 栈的最大值问题 max问题 min问题 队列的max问题

    常数时间求栈的最大值   问题描述: 一个栈stack,具有push和pop操作,其时间复杂度皆为O(1). 设计算法max操作,求栈中的最大值,该操作的时间复杂度也要求为O(1). 可以修改栈的存储 ...

  2. python16_day22【cmdb注释】

    https://github.com/willianflasky/growup/tree/master/s16/day23/learnMadKing

  3. 编译安装MariaDB-10.0.21

    一.源码编译安装gcc-5.1.0 1.下载gcc源码包 Download (HTTP): http://ftpmirror.gnu.org/gcc/gcc-5.2.0/gcc-5.2.0.tar.b ...

  4. python全栈开发从入门到放弃之递归函数的调用

    1.递归效率低,需要在进入下一次递归时保留当前的状态,见51cto博客 解决方法是尾递归,即在函数的最后一步(而非最后一行)调用自动但是python又没有尾递归,且对递归层级做了限制 必须有一个明确的 ...

  5. yii2 商品上下架

    视图层 <td><?php if($value['is_on_sale'] == 1) {?><img src="../web/images/yes.gif&q ...

  6. SHUOJ - 算法题1 矩阵连乘问题(区间dp)

    链接:http://acmoj.shu.edu.cn/problem/24/ 分析:设\(dp[i][j]\)为矩阵\(A[i:j]\)所需的最少乘法次数,则有dp方程:\(dp[i][j]=min\ ...

  7. Winter-1-F Number Sequence 解题报告及测试数据

    Time Limit:1000MS     Memory Limit:32768KB Description ​A number sequence is defined as follows:f(1) ...

  8. python os模块一些常用操作

    os.getcwd() ## 获取当前路径 os.chdir("dirpath") ## 改变目录 os.makedirs("dirname") ## 递归创建 ...

  9. win7_32下编译FFmpeg

    运行环境:  VC2010软件:                 [附:本文所用软件安装包:http://download.csdn.NET/detail/sinat_36666600/9705438 ...

  10. win764位英文版系统unicode编码问题

    出现的编码现象: 1.以*.vga格式的课件文件,当作好可读html之后,仍然不能播放,此时为Unicode编码所致: 2.在编辑TXT文档时,内容凡有中文,在保存时,会提示不能识别,当确认后,中文字 ...