• C++:析构函数


    一、什么是析构函数

    析构函数是类中一种特殊的成员函数,但其功能和构造函数是相反的,当对象结束其生命周期时,系统会自动调用该对象的析构函数进行清理工作(如释放内存中分配给该对象的空间,关闭打开的文件等)。另外析构函数没有返回值,不需要参数,也不能被重载且一个类中有且只能有一个析构函数。但和构造函数相似,析构函数的函数名和类名相同,只不过需要在函数名向加上一个~

    语法:~ 类名(){/*...析构函数体...*/}

    特别注意:

    • 如果用户没有显式地在类中定义析构函数,编译器会在类中生成一个默认的析构函数。且任何对象在被系统销毁时,都会调用该对象的析构函数。

     1 #include<iostream>
     2 #include<string>
     3 using namespace std;
     4 class Student{
     5 public:
     6     Student(){
     7         cout<<"调用了默认构造函数"<<endl;
     8     }
     9     Student(string name,int age):Name(name),Age(age){}
    10     Student(const Student& stu);//拷贝构造函数
    11     Student& operator=(const Student& stu);//赋值函数
    12     ~Student(){ //析构函数 
    13         cout<<"调用了析构函数"<<endl;
    14     } 
    15 private:
    16     string Name;
    17     int Age;
    18 }; 
    19 int main(){
    20     Student stu1;
    21     return 0;
    22 }

     • main函数中,析构函数的调用发生在语句“return 0;”之后

    二、对象的析构顺序

    先来看一个例子

     1 #include<iostream>
     2 #include<string>
     3 using namespace std;
     4 class Student{
     5 public:
     6     Student(){
     7         cout<<"调用了默认构造函数"<<endl;
     8     }
     9     Student(string name,int age,int id):Name(name),Age(age),ID(id){
    10         cout<<"创建对象ID号为"<<this->ID<<"的对象"<<endl;
    11     }
    12     Student(const Student& stu);//拷贝构造函数
    13     Student& operator=(const Student& stu);//赋值函数
    14     ~Student(){ //析构函数 
    15         cout<<"析构对象ID号为"<<this->ID<<"的对象"<<endl; 
    16     } 
    17 private:
    18     string Name;
    19     int Age;
    20     int ID;//对象的ID号 
    21 }; 
    22 int main(){
    23     Student stu1("Tomwenxing",23,1);
    24     Student stu2("Ellen",22,2);
    25     Student stu3("Jack",21,3);
    26     Student stu4("Dick",23,4);
    27     cout<<"---------------分界线---------------------"<<endl;
    28     return 0;
    29 }

    由上例可知,对象创建完毕后会被存放在内存中的一个中,因此根据栈的“先进后出”的原则,最后被创建的对象由于最晚添加到栈中,故会被最先析构;而最早创建的对象由于位于栈底,故最后才会被析构。

    三、为什么编写析构函数

    在C++中,如果用户在自定义的类中没有编写析构函数,那么编译器会在类中自动生成一个默认的析构函数,但通常情况下编译器生成的默认析构函数的函数体为空,即该析构函数什么工作也不做,例如上例中的Student类,如果不手动定义该类的析构函数,那么系统默认生成的析构函数如下:

    1 Student::~Student(){}//该析构函数什么工作也不做

    有时候我们需要析构函数在销毁对象时完成一些清理工作。例如C++要求如果用new在内存中动态开辟了空间,则必须由相应的delete对该内存空间进行释放,因此如果我们自定义的类中含有指针成员变量,并在该类的构造函数中用new为该指针在内存中动态的分配空间,那么为了避免内存泄漏,就必须在该类的析构函数中使用delete来释放在内存中动态开辟的空间:

     1 #include<iostream>
     2 #include<string>
     3 using namespace std;
     4 class Example{
     5 public:
     6     Example()=default;
     7     Example(string message,int v):ptr(new string) ,ID(v){ //用new为指针ptr分配内存空间 
     8         *ptr=message; //将信息拷贝到动态分配的内存空间中 
     9         cout<<"创建对象ID为"<<this->ID<<"的对象"<<endl;
    10     }
    11     ~Example(){
    12         cout<<"析构对象ID为"<<this->ID<<"的对象"<<endl; 
    13         delete ptr;//释放ptr所指的内存空间 
    14         ptr=NULL; //将指针ptr赋值为空 
    15         cout<<"delete完毕!"<<endl; 
    16     }
    17 private:
    18     string *ptr;//指针
    19     int ID; 
    20 };
    21 
    22 int main(){
    23     Example example1("Tomwenxing",1);
    24     Example example2("JackMa",2);
    25     return 0; 
    26 }

    再比如我们可以在构造函数中打开文件,而在析构函数中关闭文件;或在构造函数中打开和数据库的连接,而在析构函数中关闭和数据库的连接。等等......

    因此简单来说就是在构造函数中获取系统资源,而在析构函数中释放这些系统资源以便这些系统资源被重新利用。

    四、一个重要的原则——三法则(rule of three)

    如果用户显示定义了类中析构函数、拷贝构造函数或赋值函数中的任何一个,那么另外两个函数通常也必须显式定义。

    Question:什么时候需要显示定义?

    Answer:当自定义类中有指针成员变量或需要利用某种系统资源时(如文件资源、数据库资源等)时,往往需要显示定义析构函数、拷贝构造函数和赋值函数。

  • 相关阅读:
    BASE64Encoder/BASE64Decoder(转)
    对象转化为json
    Intent
    RecyclerView的单击和长按事件(转)
    selector的例子
    修改app工程名 Android Studio
    The number of method references in a .dex file cannot exceed 64K.(转)
    $(function() {})
    jQuery插件开发的两种方法及$.fn.extend的详解(转)
    myeclipse2014安装aptana3.4.0插件(转)
  • 原文地址:https://www.cnblogs.com/duwenxing/p/7450116.html
Copyright © 2020-2023  润新知