详解C++编程中的析构函数

 更新时间:2015年09月16日 18:32:18   投稿:goldensun  
这篇文章主要介绍了C++编程中的析构函数,是C++入门学习中的基础知识,需要的朋友可以参考下

C++析构函数

创建对象时系统会自动调用构造函数进行初始化工作,同样,销毁对象时系统也会自动调用一个函数来进行清理工作(例如回收创建对象时消耗的各种资源),这个函数被称为析构函数。

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

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

析构函数举例:

#include <iostream>
using namespace std;
class Student{
private:
  char *name;
  int age;
  float score;
public:
  //构造函数
  Student(char *, int, float);
  //析构函数
  ~Student();
  //普通成员函数
  void say();
};
Student::Student(char *name1, int age1, float score1):name(name1), age(age1), score(score1){}
Student::~Student(){
  cout<<name<<"再见"<<endl;
}
void Student::say(){
  cout<<name<<"的年龄是 "<<age<<",成绩是 "<<score<<endl;
}
int main(){
  Student stu1("小明", 15, 90.5f);
  stu1.say();
  
  Student stu2("李磊", 16, 95);
  stu2.say();
  
  Student stu3("王爽", 16, 80.5f);
  stu3.say();
  cout<<"main 函数即将运行结束"<<endl;
  
  return 0;
}

运行结果:

小明的年龄是 15,成绩是 90.5
李磊的年龄是 16,成绩是 95
王爽的年龄是 16,成绩是 80.5
main 函数即将运行结束
王爽再见
李磊再见
小明再见

可以看出,析构函数在 main 函数运行结束前被执行,并且调用顺序和构造函数正好相反,为了方便记忆,我们可以将之理解为一个栈,先入后出。
析构函数的执行顺序为什么是反的。
析构函数在对象被销毁前执行;要知道析构函数什么时候被调用,就要先知道对象什么时候被销毁。

对象可以认为是通过类这种数据类型定义的变量,它的很多特性和普通变量是一样的,例如作用域、生命周期等。由此可以推断,对象这种变量的销毁时机和普通变量是一样的。

总结起来,有下面几种情况:
1) 如果在一个函数中定义了一个对象(auto 局部变量),当这个函数运行结束时,对象就会被销毁,在对象被销毁前自动执行析构函数。

2) static 局部对象在函数调用结束时并不销毁,因此也不调用析构函数,只有在程序结束时(如 main 函数结束或调用 exit 函数)才调用 static 局部对象的析构函数。

3) 如果定义了一个全局对象,也只有在程序结束时才会调用该全局对象的析构函数。

4) 如果用 new 运算符动态地建立了一个对象,当用 delete 运算符释放该对象时,先调用该对象的析构函数。

注意:析构函数的作用并不是删除对象,而是在撤销对象占用的内存之前完成一些清理工作,使这部分内存可以分配给新对象使用。

C++调用构造函数和析构函数的顺序
在使用构造函数和析构函数时,需要特别注意对它们的调用时间和调用顺序。在一般情况下,调用析构函数的次序正好与调用构造函数的次序相反:最先被调用的构造函数,其对应的(同一对象中的)析构函数最后被调用,而最后被调用的构造函数,其对应的析构函数最先被调用。如例9.5所示,先执行stud2的析构函数,再执行stu1的析构函数。

可以简记为:先构造的后析构,后构造的先析构,它相当于一个栈,先进后出。

但是,并不是在任何情况下都是按这一原则处理的。对象可以在不同的作用域中定义,可以有不同的存储类别。这些会影响调用构造函数和析构函数的时机。

下面归纳一下什么时候调用构造函数和析构函数:
1) 在全局范围中定义的对象(即在所有函数之外定义的对象),它的构造函数在文件中的所有函数(包括main函数)执行之前调用。但如果一个程序中有多个文件,而不同的文件中都定义了全局对象,则这些对象的构造函数的执行顺序是不确定的。当main函数执行完毕或调用exit函数时(此时程序终止),调用析构函数。

2) 如果定义的是局部自动对象(例如在函数中定义对象),则在建立对象时调用其构造函数。如果函数被多次调用,则在每次建立对象时都要调用构造函数。在函数调用结束、对象释放时先调用析构函数。

3) 如果在函数中定义静态(static )局部对象,则只在程序第一次调用此函数建立对象时调用构造函数一次,在调用结束时对象并不释放,因此也不调用析构函数,只在main函数结束或调用exit函数结束程序时,才调用析构函数。

例如,在一个函数中定义了两个对象:

void fn(){
  Student stud1; //定义自动局部对象
  static Student stud2; //定义静态局部对象
}


在调用fn函数时,先调用stud1的构造函数,再调用stud2的构造函数,在fn调用结束时,stud1是要释放的(因为它是自动局部对象),因此调用stud1的析构函数。而stud2 是静态局部对象,在fn调用结束时并不释放,因此不调用stud2的析构函数。直到程序结束释放stud2时,才调用stud2的析构函数。可以看到stud2是后调用构造函数的,但并不先调用其析构函数。原因是两个对象的存储类别不同、生命周期不同。

相关文章

  • C++类中的static和const用法实例教程

    C++类中的static和const用法实例教程

    这篇文章主要介绍了C++类中的static和const用法,是C++面向对象程序设计中非常重要的概念,需要的朋友可以参考下
    2014-08-08
  • Qt4和Qt5的信号和槽的使用区别

    Qt4和Qt5的信号和槽的使用区别

    本文主要介绍了Qt4 和 Qt5 的信号和槽的连接 connect 与断开 disconnect 区别,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-06-06
  • C/C++线程退出的四种方法小结

    C/C++线程退出的四种方法小结

    本文主要介绍了C/C++线程退出的四种方法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • Windows10配置VSCode C++环境(超详细,面向小白以及大佬们)

    Windows10配置VSCode C++环境(超详细,面向小白以及大佬们)

    这篇文章主要介绍了Windows10配置VSCode C++环境(超详细,面向小白以及大佬们),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • C++深入分析回顾函数重载

    C++深入分析回顾函数重载

    C++ 允许多个函数拥有相同的名字,只要它们的参数列表不同就可以,这就是函数的重载(Function Overloading),借助重载,一个函数名可以有多种用途
    2022-06-06
  • Qt使用SqlLite实现权限管理的示例代码

    Qt使用SqlLite实现权限管理的示例代码

    本文主要介绍了Qt使用SqlLite实现权限管理的示例代码,管理员针对不同人员进行权限设定,具有一定的参考价值,感兴趣的可以了解一下
    2023-09-09
  • C++中栈结构建立与操作详细解析

    C++中栈结构建立与操作详细解析

    我们可以把栈理解成一个大仓库,放在仓库门口(栈顶)的货物会优先被取出,然后再取出里面的货物。而从数据的逻辑结构来看,栈结构起始就是一种线性结构
    2013-10-10
  • C语言中文件处理全攻略详解

    C语言中文件处理全攻略详解

    这篇文章主要为大家详细介绍了C语言中文件处理的相关知识,包括创建、写入、追加操作解析,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下
    2024-01-01
  • VS中的scanf_s函数和scanf用法及说明

    VS中的scanf_s函数和scanf用法及说明

    这篇文章主要介绍了VS中的scanf_s函数和scanf用法及说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • C语言深入讲解指针与结构体的使用

    C语言深入讲解指针与结构体的使用

    指针提供了对地址操作的一种方法,因此,使用指针可使得C语言能够更高效地实现对计算机底层硬件的操作。另外,通过指针可以更便捷地操作数组。C数组允许定义可存储相同类型数据项的变量,结构是C编程中另一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项
    2022-05-05

最新评论