一、认识析构函数

在我的前一篇博客介绍了类的构造函数。http://www.cnblogs.com/MrListening/p/5557114.html。

这里我们来简单说说类的析构函数,它是类的一个成员函数,名字由波浪号加类名构成。看它的名字我们大概就能联想到他功能,是执行与构造函数相反的操作:释放对象使用的资源,并销毁非static成员。

同样的,我们来看看析构函数的几个特点:

1.函数名是在类名前加上~,无参数且无返回值。

2.一个类只能有且有一个析构函数,如果没有显式的定义,系统会生成一个缺省的析构函数(合成析构函数)。

3.析构函数不能重载。每有一次构造函数的调用就会有一次析构函数的调用。

拿程序说话:

//by Mr_Listening,06 08 2016
class Date
{
public:
Date(int year=,int month=,int day=)
: _month(year), _year(month), _day(day)
{ }
~Date()
{
cout << "~Date()" << this << endl;
}
private:
int _year=;
int _month;
int _day;
};
void test()
{
Date d1;
}
int main()
{
test();
return ;
}

在test()函数中构造了对象d1,那么在出test()作用域d1应该被销毁,此时将调用析构函数,下面是程序的输出。当然在构建对象时是先调用构造函数的,在这里就不加以说明了。

我们知道,在构造函数中,成员的在初始化是在函数体执行前完成的,并按照成员在类中出现的顺序进行初始化,而在析构函数中,首先执行函数体,然后再销毁成员,并且成员按照初始化的逆序进行销毁。

二、销毁,清理?

我们一直在说析构函数的作用是在你的类对象离开作用域后释放对象使用的资源,并销毁成员。那么到底这里所说的销毁到底是什么?那么继续往下看:

void test ()

{

int a=10;

int b=20;

}

回想我们在一个函数体内定义一个变量的情况,在test函数中定义了a和b两个变量,那么在出这个函数之后,a和b就会被销毁(栈上的操作)。那么如果是是一个指向动态开辟的一块空间的指针,我们都知道需要自己进行free,否则会造成内存泄漏。

说到这里,其实在类里面的情况和这是一样的,这就是合成析构函数体为空的原因,函数并不需要做什么,当类对象出作用域时系统会释放你的内置类型的那些成员。但是像上面说的一样,如果,我的成员里有一个指针变量并且指向了一块你动态开辟的内存,那么像以前那样也需要自己来释放,此时就需要在析构函数内部写你的释放代码,这样在调用析构函数的时候就可以把你所有的资源进行释放。(其实这才是析构函数有用的地方,对吗)

那么还有一点,当类类型对象的成员还有一个类类型对象,那么在析构函数里也会调用这个对象的析构函数。

三、析构函数来阻止该类型对象被销毁?

我们如果不想要析构函数来对对象进行释放该怎么做呢,不显式的定义显然是不行的,因为编译器会生成默认的合成析构函数。之前我们知道了如果想让系统默认生成自己的构造函数可以利用default,那么其实还有一个东西叫做delete。

class Date
{
public:
Date(int year=1990,int month=1,int day=1)
: _year(year),_month(month), _day(day)
{ }
~Date() = delete; private:
int _year=1990;
int _month;
int _day;
};

     如果我这么写了,又在底下创建Date类型的对象,那么这个对象将是无法被销毁的,其实编译器并不允许这么做,直接会给我们报错。

但其实是允许我们动态创建这个类类型对象的,像这样:Date* p = new Date;虽然这样是可行的,但当你delete p的时候依然会出错,原因就不用说了吧

所以既然这样做的话既不能定义一个对象也不能释放动态分配的对象,所以还是不要这么用为好喽。

四、注意喽

一般在你显式的定义了析构函数的情况下,应该也把拷贝构造函数和赋值操作显式的定义。为什么呢??

看下面的改动:

class Date
{
public:
Date(int year=1990,int month=1,int day=1)
: _year(year),_month(month), _day(day)
{
p = new int;
}
~Date()
{
delete p;
} private:
int _year=1990;
int _month;
int _day;
int *p;
};

  成员中有动态开辟的指针成员,在析构函数中对它进行了delete,如果不显式的定义拷贝构造函数,当你这样:Date d2(d1)来创建d2,我们都知道默认的拷贝构造函数是浅拷贝,那么这么做的结果就会是d2的成员p和d1的p是指向同一块空间的,呢么调用析构函数的时候回导致用一块空间被释放两次,程序会崩溃的哦!

最后,

我们知道析构函数是可以调用的,那么构造函数可不可以呢?是怎样的使用环境

C++之类的析构函数的更多相关文章

  1. .NET 基础 一步步 一幕幕[面向对象之构造函数、析构函数]

    构造函数.析构函数 构造函数: 语法: //无参的构造函数 [访问修饰符] 函数名() :函数名必须与类名相同. //有参的构造函数 [访问修饰符] 函数名(参数列表):函数名必须与类名相同. 作用: ...

  2. 【C#】析构函数

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

  3. c++虚析构函数

    虚析构函数的作用主要是当通过基类指针删除派生类对象时,调用派生类的析构函数(如果没有将不会调用派生类析构函数) #include <iostream> using namespace st ...

  4. 转:Delphi2010新发现-类的构造和析构函数功能

    Delphi2010发布了. 虽然凭着对Delphi的热爱第一时间就安装了,但是现在可能是年纪大了,对新事物缺乏兴趣了.一直都没有仔细研究. 今天有点时间试了一下新功能. 本来C#和Delphi.NE ...

  5. c++单例模式为什么不在析构函数中释放静态的单例对象(转)

    需要清楚一下几点:   1.单例中的 new 的对象需要delete释放.   2.delete释放对象的时候才会调用对象的析构函数.   3.如果在析构函数里调用delete,那么程序结束时,根本进 ...

  6. C++构造函数/析构函数 设置成private的原因

    C++构造函数/析构函数 设置成private的原因 标签(空格分隔): c/c++ 将构造函数,析构函数声明为私有和保护的,那么对象如何创建? 已经不能从外部调用构造函数了,但是对象必须被构造,应该 ...

  7. 关于GC和析构函数的一个趣题

    这个有趣的问题感谢装配脑袋友情提供. 请看如下代码: public class Dummy { public static Dummy Instance; ; ~Dummy() { Instance ...

  8. C++构造函数和析构函数

    构造函数简介 在上一个章节我们在创建好类的对象之后,首先对它的每一个成员属性赋值之后再对它们进行输出操作,如果不赋值就输出,这些值就会是垃圾值.而为了代码的简介,一次性为所有成员属性初始化,C++的类 ...

  9. virtual 修饰符与继承对析构函数的影响(C++)

    以前,知道了虚函数表的低效性之后,一直尽量避免使用之.所以,在最近的工程中,所有的析构函数都不是虚函数.今天趁着还书的机会到图书馆,还书之后在 TP 分类下闲逛,偶然读到一本游戏编程书,里面说建议将存 ...

  10. 谈一谈.net析构函数对垃圾回收的影响

    之前忘了说了 代码都是在Release模式下运行的,现在补充上. 这里说析构函数,其实并不准确,应该叫Finalize函数,Finalize函数形式上和c++的析构函数很像 ,都是(~ClassNam ...

随机推荐

  1. codeforces 671C Ultimate Weirdness of an Array 线段树+构造

    题解上说的很清楚了,我照着写的,表示膜拜题解 然后时间复杂度我觉得应该是O(nlogn),虽然常数略大,预处理和倒着扫,都是O(nlogn) #include <stdio.h> #inc ...

  2. HDU 3642 Get The Treasury 线段树+分层扫描线

    http://www.acmerblog.com/hdu-3642-get-the-treasury-6603.html 学习:三维就是把竖坐标离散化分层,每一层进行线段树二维面积并就好了

  3. HNU OJ10320 穿越火线 简单模拟

    穿越火线 Time Limit: 10000ms, Special Time Limit:25000ms, Memory Limit:65536KB Total submit users: 12, A ...

  4. as3+java+mysql(mybatis) 数据自动工具(七) - 完结

    autoscript packed 文件地址:http://pan.baidu.com/s/1dDvgcO5 如果需要项目源码的话,可以留下邮箱,先声明一下,该工具主要是为了实现自动同步输出代码类文件 ...

  5. 五指cms筛选功能的实现:

    筛选功能的实现: $_POST['page_urlrule'] = 'tuan-{$pinpai}-{$renqun}-{$type}-{$price}-{$area}-{$tese}-{$st}-{ ...

  6. 命令cp

    cp 源 目标cp -r  递归复制整个目录cp -v  显示复制的详细信息

  7. Unity3D入门之JavaScript

    刚刚接触Unity3D游戏引擎,这里做点学习笔记.下面是我建立的简单场景,左侧的Hierarchy(层次)视图里显示了场景中所有游戏对象,这些基本对象可以从Create下拉菜单里创建.当你点击某个对象 ...

  8. 纯CSS完美实现垂直水平居中的6种方式

    前言 由于HTML语言的定位问题,在网页中实现居中也不是如word中那么简单,尤其在内容样式多变,内容宽高不定的情况下,要实现合理的居中也是颇考验工程师经验的.网上讲居中的文章很多,但是都不太完整,所 ...

  9. delphi 常用属性+方法+事件+代码+函数

    内容居中(属性) alignment->tacenter mome控件 禁用最大化(属性) 窗体-> BorderIcons属性-> biMaximize-> False 让鼠 ...

  10. A Tour of Go Exercise: Fibonacci closure

    Let's have some fun with functions. Implement a fibonacci function that returns a function (a closur ...