-
2021-01-17 17:48:57
析构函数也是一个在类中跟构造函数类似的特殊功能的成员函数,作用与构造函数相反,是在对象的声明周期结束的时候会被自动调用.在C++中析构函数的名字跟类名相同,并在前面带上一个取反的符号~,表达的意思也跟构造函数的过程相反.
默认情况下,如果类没有定义自己的析构函数,编译器会自动为该类生成一个默认的析构函数,只不过函数体是空的,也就是什么都没做.所有,如果需要在对象被删除的时候做一些操作的话,就得自己定义析构函数.
以下几种情况会自动调用析构函数:
①如果一个函数中定义了一个局部变量的对象,那么当这个函数执行结束时也就是该变量对象生命周期结束的时候,所以析构函数会被自动调用.
②全局变量或者static类型的变量,他们的生命周期一般是在程序退出的时候,该对象的析构函数才会被调用.
③如果是用new操作符动态的创建了一个对象,只有当用delete进行释放该对象的时候,析构函数才会被调用.
析构函数的作用:
那构造函数来说,构造函数是新建对象吗?不是,而是在对象被创建出来后自动被调用的,用来初始化相关信息的函数.同理:析构函数也不是用来删除对象的,而是当对象被删除的时候自动被调用的,用来做一些对象被删除之前的清理工作,只有对象的生命周期结束,那么程序就自动执行析构函数来完成这个工作.
析构函数的特点:
析构函数不返回任何值,没有函数类型,也没有任何函数的参数.析构函数不能被重载,所以,一个类中可以有多个构造函数,但只有一个析构函数.
析构函数使用示例:CStudent::~CStudnet() { cout<<"~CStudent() callec."<<endl; }
//本文来源于VC驿站,仅作为个人学习记录
更多相关内容 -
详解C++中的析构函数
2020-12-17 04:29:04析构函数(Destructors),是对象的成员函数,没有返回值也没有参数,且一个类只有一个析构函数,当对象被销毁的时候调用,被销毁通常有这么几个情况。 函数执行结束 程序执行结束 程序块包含的局部变量 delete... -
c++析构函数
2021-01-07 18:55:14在main函数中创建了t0,t1,t2,t3几个对象,这里先说一下C++创建对象的三种不同方式: 1、Test p1(1); //栈中分配内存 2、Test p2 = Test(2); //栈中分配内存,跟方法1相同,是方法1的完整模式 3、Test *p3 = new ...c++析构函数
首先我们来看一下有关析构函数的文字描述
1、定义
析构函数(destructor) 与构造函数相反,当对象结束其生命周期,如对象所在的函数已调用完毕时,系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,delete会自动调用析构函数后释放内存)。
2、 作用:对象消亡时,自动被调用,用来释放对象占用的空间
3、特点:
(1) 名字与类名相同
(2) 在前面需要加上"~"
(3) 无参数,无返回值
(4) 一个类最多只有一个析构函数
(5) 不显示定义析构函数会调用缺省析构函数#include<iostream> using namespace std; class Test { int id; public: Test() { } Test(int i) { id = i; } ~Test() { cout<<"ID: "<<id<<" destruction function is invoked!"<<endl; }; }; int main() { Test t0(0); //栈中分配 Test t1[3]={1,1,1}; //栈中分配 Test *t2 = new Test(2); //堆中分配 delete t2; Test *t3 = new Test[3]{3,3,3}; //堆中分配 delete []t3; cout<<"------End of Main-------"<<endl; return 0; }
在给出运行结果以前有必要说一下,我在vs2012的编译器里也运行了这段代码。但是其中
Test *t3 = new Test[3]{3,3,3};
这行代码是有错误的,我去查阅了相关的博客资料发现,在C++11中引进了这一新功能,即用new申请动态数组时可以直接初始化,形式如下:int* p = new int[cnt](); //其中cnt长度和int类型都可以自己定义。 int* p = new int[cnt]{ };
而且可以用这个方式给每个成员赋值。
int* a = new int[10] { 1,2,3,4,5,6,7,8,9,10 };
所以说上面的
Test *t3 = new Test[3]{3,3,3};
语句就应该是没问题的,下面给出运行结果。
解释:
在main函数中创建了t0,t1,t2,t3几个对象,这里先说一下C++创建对象的三种不同方式:1、Test t0(0); //栈中分配内存 2、Test t1[3]={1,1,1}; //栈中分配内存 3、Test *t2 = new Test(2); //堆中分配内存 4、Test *t3 = new Test[3]{3,3,3}; //堆中分配内存
方法1、2中都是在栈中分配内存,在栈中内存由系统自动的去分配和释放,而使用new创建的指针对象是在堆中分配内存,当不需要该对象时,需要我们手动的去释放(delete),否则会造成内存泄漏。
在上述程序中,t0和t1都是栈中的对象,在程序结束时由系统来释放,因此出现在-----End of Main----之后。t2,t3是new出来的堆中对象,所以需要手动的delete释放,因此出现在最前面。另外有一点发现,就是栈中对象的释放顺序,是后定义的先释放,经过几次验证也如此,我想这恰好应征了栈的后进先出的特征。(先释放1,后释放0)
class Test { int id; public: Test(int i) { id = i; } ~Test() { cout<<"ID: "<<id<<" destruction function is invoked!"<<endl; }; }; Test t0(0); //最先创建的对象,最后释放 void Func() { static Test t1(1); //创建静态对象,会在整个程序结束时自动释放 Test t2(2); //在Func结束时自动释放 cout<<"-----Func-----"<<endl; } int main() { Test t3(3); t3 = 10; //类型转换构造函数,这里会创建临时对象,将int型转成Test类型对象, //在赋值结束后,临时变量销毁 cout<<"------Begin of Main-------"<<endl; { Test t4(4); //花括号代表作用域,不需要等到main方法结束就释放了 } Func(); //进入Func函数 cout<<"------End of Main-------"<<endl; return 0; }
那让我们先分析一波 先是t3,t3创建完成以后想要把10赋值过来,但是一个是int类型,一个是Test,这里就会创建临时对象,将int型转成Test类型对象,在赋值结束后,临时变量销毁(把临时创建的对象得10赋值给了t3),销毁临时对象,调用一次析构函数,然后是------Begin of Main-------,到了t4,因为是在花括号里,直接调用了一次析构函数,不需要等到main方法结束,(此处如果没有花括号那么它应该在哪里呢,答案当然是在t3前面 也就是------End of Main-------之后的10前面),到了Func(); 里面的t1和t2,t1静态对象,会在整个程序结束时自动释放,t2在Func()结束时释放,所以先------Func------在调用析构函数,然后------End of Main-------,接着是释放t3,静态t1,最前面最先定义的t0;
-
C++析构函数定义和使用
2021-06-10 20:22:40析构函数(destructor)是一个特殊的成员函数,它的作用与构造函数相反,它的名字是类名的前面加一个“~”符号。在C++中“~”是位“取反”运算符,从这一点可以想到:析构函数是与构造函数作用相反的函数。例如:...析构函数
2.1 析构函数定义和使用
析构函数(destructor)是一个特殊的成员函数,它的作用与构造函数相反,它的名字是类名的前面加一个“~”符号。在C++中“~”是位“取反”运算符,从这一点可以想到:析构函数是与构造函数作用相反的函数。例如:
class student{
public:
student()//构造函数
{
}
~student() //析构函数
{ }
void print(){}
};
可以看到,定义了一个student类。然后,定义student类的构造函数和析构函数。其中,析构函数的定义如下:
~student(){ }
那么,函数名是类名前面添加取反符号“~”,而且,函数没有参数。
当对象的生命周期结束的时候,就会自动执行析构函数。如果出现以下几种情况,程序就会执行析构函数:
(1) 如果在一个函数中定义了一个对象,那么,该对象就是局部对象,当这个函数被调用结束时,对象的生命周期结束。此时,对象应该释放(销毁),在对象释放(销毁)前自动执行析构函数。
(2) static 局部对象在函数调用结束时对象并不释放(销毁),因此,不调用析构函数,只在main() 函数结束或调用exit()函数结束程序的时候,才调用static局部对象的析构函数。
因为static局部对象的生命周期是整个程序运行过程,所以,只有程序结束运行的时候,static局部对象的生命周期才结束,才执行类的析构函数。
(3) 如果定义了一个全局对象,全局对象的生命周期是整个程序运行过程,所以,当程序结束运行的时候,全局对象才销毁,此时,调用该全局对象的析构函数。
(4) 如果用new运算符动态地建立了一个对象,当用delete运算符释放该对象时,先调用该对象的析构函数。
析构函数的作用并不是删除对象,而是在撤销对象占用的内存之前,完成一些清理工作。使这部分内存可以被程序分配给新对象使用。程序设计者要设计好析构函数,以完成所需的功能,只要对象的生命周期结束,程序就会自动执行析构函数来完成这些工作。
析构函数不返回任何数值,也没有函数类型 和 函数参数。由于没有函数参数,因此,它不能被重载。一个类可以有多个构造函数,但是,只能有一个析构函数。
一般情况下,类的设计者应当在声明类的同时定义析构函数,以指定如何完成“清理”的工作。如果用户没有定义析构函数,C++编译系统会自动生成一个 默认析构函数,但是,它只是有析构函数的名称和形式,实际上什么操作都不进行。想让析构函数完成任何工作,都必须在定义的析构函数中执行。
如下是一个程序测试例子,讲解构造函数和析构函数的使用。
程序运行结果如下:
在main()函数中,定义一个if(1){}代码块,在代码块中定义stud局部变量。当退出代
码块的时候,销毁stud局部变量,看到析构函数的调用。
所以,我们看到对象销毁的时候,自动调用析构函数。析构函数是不可以手动调用的。是对象销毁的时候,由系统自动调用。
所以,对象销毁的时候,我们想释放一些资源,就可以放在析构函数中操作。例如,student类中的name, addr是动态申请的内存。那么,在析构函数中就释放这些内存。
韦凯峰 Linux C/C++ 程序设计教程,Linux 系统编程,Openwrt 系统开发,微信:13926572996,QQ:1523520001,博客:www.mylinux.vip
-
C++析构函数
2019-09-23 08:45:21同样的,我们来看看析构函数的几个特点: 函数名是在类名前加上~,无参数且无返回值。 一个类只能有且有一个析构函数,如果没有显式的定义,系统会生成一个缺省的析构函数(合成析构函数)。 因为无参数无返回值...C++析构函数
一、认识析构函数
析构函数也是一种特殊的成员函数。它执行与构造函数相反的操作,通常用于撤消对象时的一些清理任务,如释放分配给对象的内存空间等。
同样的,我们来看看析构函数的几个特点:
- 函数名是在类名前加上~,无参数且无返回值。
- 一个类只能有且有一个析构函数,如果没有显式的定义,系统会生成一个缺省的析构函数(合成析构函数)。
- 因为无参数无返回值析构函数不能重载。每有一次构造函数的调用就会有一次析构函数的调用。
- 当撤消对象时,编译系统会自动地调用析构函数。 如果程序员没有定义析构函数,系统将自动生成和调用一个默认析构函数,默认析构函数只能释放对象的数据成员所占用的空间,但不包括堆内存空间。
class Data{ public: Data(int year=2019,int month=9,int day=23):_year(year),_month(month),_day(day){} ~Data(){ cout<<"~Data()"<<this<<endl; } private: int _year=1990; int _month; int _day; }; void test(){ Data test1; } int main(){ test(); return 0; }
在test()函数中构造了对象d1,那么在出test()作用域d1应该被销毁,此时将调用析构函数,下面是程序的输出。当然在构建对象时是先调用构造函数的,在这里就不加以说明了。
析构函数被调用的两种情况
1)若一个对象被定义在一个函数体内,当这个函数结束时,析构函数会被自动调用。
2)若一个对象在使用过程中运用new运算符进行动态创建,在使用delete释放时,自动调用析构函数。
二、销毁操作
析构函数在作用完类对象离开作用域后释放对象使用的资源,并销毁成员。
void test(){ int a=1; int b=2; }
在一个函数体内定义一个变量,在test函数中定义a和b两个变量,在出了test函数后,a和b就会被销毁(栈上的操作)。如果是一个指向动态开辟的一块空间的指针(new,malloc),我们都需要进行free,否则就会内存泄露问题。
当类类型对象的成员还有一个类类型对象,那么在析构函数里也会调用这个对象的析构函数。
缺省的析构函数
每个类都必须有一个析构函数。
如果类中没有显式地为一个类定义析构函数,编译系统会自动地生成一个缺省的析构函数
类名::析构函数命(){}
class Date{ public: Date(char *){ str=new char[max_len]; } ~Date(){ delete []str;} void get_info(char *); void send_info(char *); private: char *str; int max_len; };
析构函数阻止该类型对象被销毁
我们如果不想要析构函数来对对象进行释放该怎么做呢,不显式的定义显然是不行的,因为编译器会生成默认的合成析构函数。之前我们知道了如果想让系统默认生成自己的构造函数可以利用default,那么其实还有一个东西叫做delete。
class Date{ public: Date(int year=2019,int month=9,int day=1):_year(year),_month(month),_day(day){} ~Date()=delete; private: int _year=2019; int _month; int _day; };
这么写了,又在底下创建Date类型的对象,那么这个对象将是无法被销毁的,其实编译器并不允许这么做,直接会给我们报错。
但可以使用动态创建这个类类型对象的,像这样:Date* p = new Date;虽然这样是可行的,但当你delete p的时候依然会出错。既不能定义一个对象也不能释放动态分配的对象,所以还是不要这么用为好。
一般在显式的定义了析构函数的情况下,应该也把拷贝构造函数和赋值操作显式的定义。
class Date{ public: Date(int year=2019,int month=9,int day=1):_year(year),_month(month),_day(day){ p=new int; } ~Date(){ delete p; } private: int _year=2019; int _month; int _day; int *p; };
成员中有动态开辟的指针成员,在析构函数中对它进行了delete,如果不显式的定义拷贝构造函数,当你这样:Date d2(d1)来创建d2,我们都知道默认的拷贝构造函数是浅拷贝,那么这么做的结果就会是d2的成员p和d1的p是指向同一块空间的,那么调用析构函数的时候回导致用一块空间被释放两次,程序会崩溃。
调用构造函数与析构函数的顺序
1)一般顺序
调用析构函数的次序正好与调用构造函数的次序相反,最先被调用的构造函数,其对应的构造函数最后被调用,而最后被调用的构造函数,其对应的析构函数最先被调用。
对象1构造函数->对象2的构造函数->对象3的构造函数->对象3的析构函数->对象2的析构函数->对象1的析构函数
2)全局对象
在全局范围中定义的对象(即在所有函数之外定义的对象),它的构造函数在所有函数执行之前调用。在程序流程离开其作用域时,调用该全局对象的析构函数。(包括main函数)
3)auto局部对象
局部自动对象(例函数中定义的对象),则在建立对象时调用其构造函数。如果函数被多次调用,则每次调用时都要调用构造函数。在函数调用结束、对象释放时先调用析构函数。
4)static局部对象
在函数中定义静态局部对象,则只在程序第一次盗用此函数建立对象时调用构造函数一次,在调用结束时对象并不释放,因此也不调用析构函数,只在main函数结束或调用exit函数结束程序时,才调用析构函数。
对象的生存期
对象生存期不同分为:局部对象、全局对象、静态对象、动态对象。
(1)局部对象
当对象被定义时,调用构造函数,该对象被创建;当程序退出该对象所在的函数体或程序块时,调用析构函数,对象被释放。
局部对象在被定义在一个函数体或程序块内的,它的作用域限定在函数体或程序块内,生存期比较短。
(2)全局对象
当程序开始运行时,调用构造函数,该对象被创建;当程序结束时,调用析构函数,该对象被释放。
静态对象时被定义在一个文件中,它的作用域从定义是起到文件结束为止,生存期长。
(3)静态对象
当程序中定义静态对象时,调用构造函数,该对象被创建;当整个程序结束时,调用析构函数,对象被释放。
全局对象是被定义在某个文件中,它的作用域包含在该文件的整个程序中,生存期最长。
(4)动态对象
执行new运算符调用构造函数,动态对象被创建;用delete释放对象时,调用析构函数
动态对象由程序员掌握,它作用域与生存期是有new和delete之间的时间决定的。
-
C++ 类 析构函数
2019-11-03 10:49:04C++ 类 析构函数 阅读目录 一、析构函数的定义 二、析构函数的调用 ...一个类最多只能有一个析构函数。析构函数不返回任何值,没有函数类型,也没有函数参数,因此它不能被重载。 构造函数可能... -
深入探索C++对象模型(九) 析构函数 (以及显式定义的析构函数问题、析构函数Rules of Three)
2018-06-03 17:30:40如果类没有定义析构函数,那么只有类中含有成员对象(或者本类的基类)拥有析构函数的情况下,编译器才会合成一个出来,否则析构函数被视为不要,也就不需要合成。例如,如下类,虽然Point类拥有虚函数:[cpp] view... -
[C++]8.3.4 析构函数的定义与使用
2022-03-28 16:36:36析构函数的作用; 为类定义析构函数; 关于析构函数的几点说明; 复杂对象的构造函数和析构函数调用; 使用构造函数实现强制类型转换。 -
浅析:类只能有一个析构函数
2015-04-01 12:42:11而构造函数是可以有参数的,但是析构函数是不能有参数的。 我们知道类可以有多个构造函数,这些构造函数是重载函数的关系,也就是说函数名都是相同的,区别它们主要靠参数的不同(参数个数和参数类型)。 但是由于析... -
C++——构造函数、析构函数以及复制构造函数
2021-03-09 16:28:49文章目录一、构造函数1.1 构造函数是什么?1.2 为什么要有构造函数...C++中,构造函数是一种特殊的成员函数,在每次创建一个类的时候编译器都会默认调用构造函数进行初始化。 1.2 为什么要有构造函数? 构造函数的作用 -
构造函数与析构函数的问题总结
2022-04-23 16:42:38问题四:构造函数能否声明为虚函数或者纯虚函数,析构函数呢? 问题五:构造函数、析构函数、可否声明为内联函数inline 问题六:构造函数和析构函数可以调用虚函数吗? 问题七:什么情况会自动生成默认构造函数?... -
PHP之析构函数
2018-07-19 14:55:46随着面向对象编程的普遍展开,面向对象展现了其中很多有趣的问题。相信很多初学者学习php面向对象时会接触两个函数,构造函数与析构函数。... 析构函数常常处理的事务是一些资源释放的工作,比如前面有fopen(),... -
析构函数为虚函数
2019-06-20 12:37:14多态是面向对象的一个基本属性,包括静态多态(编译阶段)和动态多态(运行阶段),静态多态主要是指函数参数不同产生的多态性,是在编译阶段可以识别的一种多态机制,而运行时多态则主要用于基类指针指向派生类对象... -
【C++要笑着学】类的默认成员函数详解 | 构造函数 | 析构函数 | 构造拷贝函数
2022-03-08 18:02:17我是柠檬叶子C,本章将继续讲解C++中的面向对象的知识点,本篇主要讲解默认成员函数中的构造函数、析构函数和拷贝构造函数。还是和以前一样,我们将由浅入深地去讲解,以 "初学者" 的角度去探索式地学习。会一步步地... -
c++中的析构函数
2019-04-09 20:55:46印象中c++的析构函数是会自动调用。但是今天运行程序的时候,却没有进入到我写的析构函数,让我不禁怀疑,最终到底析构了没有。还是暗自调用了系统的析构。所以来记载一下析构的知识。 以下属转载,原文博客地址:... -
C++的四个默认函数(构造函数,析构函数,拷贝函数,赋值函数)
2021-02-21 17:17:29析构函数三. 拷贝构造函数1.浅拷贝2.深拷贝四. 赋值函数 在C++中,对于一个类,C++的编译器都会为这个类提供四个默认函数,分别是: A() //默认构造函数 ~A() //默认析构函数 A(const A&) //默认拷贝构造... -
C++ 类和对象(二):构造函数、析构函数、拷贝构造函数、运算符重载
2020-04-19 22:57:02析构函数 拷贝构造函数 运算符重载 class Date { }; 可以看到,上面那个类没有任何成员,是一个空类,但是它真的什么都没有吗?其实一个类在我们不写的情况下,都会生成6个默认的成员函数 分别是构造函数,析构... -
4 构造函数与析构函数【C++】
2022-04-26 13:04:574. 构造函数与析构函数)【C++】 -
【C++】类的构造函数与析构函数笔记
2019-08-06 14:26:00目录 0. 整体概述为什么要引入构造函数 1. 声明和定义构造函数 程序声明对象时,将自动调用构造函数 1.1 成员名和参数名 ...什么时候调用析构函数呢? 5 改进Stock类 stock10.h Stock10.cpp ... -
C++类中的6个默认函数之构造函数、析构函数、拷贝构造函数、赋值运算符重载函数
2018-11-30 22:46:05类中6个默认函数,如果在定义类时没有定义这6... 析构函数 拷贝构造函数 赋值运算符重载函数 取地址操作符重载函数 const修饰的取地址操作符重载函数 构造函数 1.构造函数与类名相同,并且没有返回值 2... -
组合类构造函数、析构函数、拷贝构造函数的调用顺序
2021-02-16 20:11:02这些天在看C++的过程中一直搞不太懂构造函数和析构函数的调用顺序,特别是析构函数,不带参数不好进行测试,这里把这几天遇到的问题写了个代码跑了一下,和大家分享一下,写的有不对的地方,欢迎大家批评指正。... -
新手学C/C++:析构函数是否必须为虚函数?什么情况下才应该定义析构函数为虚函数?
2018-12-17 10:22:06多态是面向对象的一个基本属性,包括静态多态(编译阶段)和动态多态(运行阶段),静态多态主要是指函数参数不同产生的多态性,是在编译阶段可以识别的一种多态机制,而运行时多态则主要用于基类指针指向派生类对象... -
C++类——派生类的构造函数与析构函数
2018-07-11 17:10:32每个类都分别定义了它的对象被初始化的方式, 类通过一个或几个特殊的成员函数来控制器对象的初始化过程, 这些函数叫做构造函数。 构造函数的任务是初始化对象的数据成员, 无论何时只要类的对象... -
关于构造函数,拷贝构造函数,析构函数的调用顺序(1)
2020-08-14 18:31:13导言 对象是由“底层向上”开始构造的,当建立一个对象时,首先调用基类的构造函数,然后调用下一个派生...1.构造函数不能有返回值 2.缺省构造函数时,系统将自动调用该缺省构造函数初始化对象,缺省构造函数会将所有数 -
C++中的指针类型与构造函数,析构函数
2022-04-10 15:07:09指针只是指向了一个内存地址,但是当存内存中取值的时候,系统不知道你要从当前指针指向的地址,取几个字节,指定了指针的类型后,系统就知道取几个字节了。 char类型取1个字节,short类型取2个字节,int类型去4个... -
c++中构造函数及析构函数特性
2017-10-02 18:10:273、c++规定,如果一个类没有提供任何的构造函数,那么c++编译器会提供一个默认的构造函数,且这个默认的构造函数是不带参数的构造函数,它只负责对象的创建,不能进行对象的初始化。 4、只要一个类定义了一个构造... -
C++析构函数释放对象的空间顺序。
2019-01-14 16:13:58一、定义 1. 作用:对象消亡时,自动被调用,用来释放... (4) 一个类最多只有一个析构函数 (5) 不显示定义析构函数会调用缺省析构函数 二、用法 1.普通用法 代码: class Test { int id; public: Test...