析构函数 订阅
析构函数(destructor) 与构造函数相反,当对象结束其生命周期,如对象所在的函数已调用完毕时,系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,delete会自动调用析构函数后释放内存)。 展开全文
析构函数(destructor) 与构造函数相反,当对象结束其生命周期,如对象所在的函数已调用完毕时,系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,delete会自动调用析构函数后释放内存)。
信息
外文名
destructor
命    名
与类名相同,在前面加位取反符~
应用学科
计算机科学
相    反
构造函数
中文名
析构函数
目    的
清理善后” 的工作
析构函数函数介绍
与构造函数相反,当对象结束其生命周期,如对象所在的函数已调用完毕时,系统会自动执行析构函数。以C++语言为例:析构函数名也应与类名相同,只是在函数名前面加一个位取反符~,例如~stud( ),以区别于构造函数。它不能带任何参数,也没有返回值(包括void类型)。只能有一个析构函数,不能重载。如果用户没有编写析构函数,编译系统会自动生成一个缺省的析构函数(即使自定义了析构函数,编译器也总是会为我们合成一个析构函数,并且如果自定义了析构函数,编译器在执行时会先调用自定义的析构函数再调用合成的析构函数),它也不进行任何操作。所以许多简单的类中没有用显式的析构函数。 [1] 
收起全文
精华内容
下载资源
问答
  •  析构函数的工作方式是:底层的派生类(most derived class)的析构函数先被调用,然后调用每一个基类的析构函数。  因为在C++中,当一个派生类对象通过使用一个基类指针删除,而这个基类有一个非虚的析构函数,...
  • 析构函数的作用是当对象生命期结束后,收回对象占用的资源,析构函数的特点是: 1、析构函数名是在类名前加以符号“~”。 2、析构函数没有参数、返回类型和修饰符。 3、一个类中至多有一个析构函数,如果程序员...
  • 主要介绍了C++中虚析构函数的作用及其原理分析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • 要求有构造函数、析构函数,完成赋值、显示、计算矩形的面积等接口,并编写main函数进行测试。 class Rect {public: int Area_int(); Rect(int l, int w); ~Rect(); private: int nLength; int nWidth; }; 2...
  • C#析构函数

    2018-04-12 11:15:07
    析构函数 finalizer destructor 整理的关于析构函数的描述以及介绍
  • 详解C++ 编写String 的构造函数、拷贝构造函数、析构函数和赋值函数  编写类String 的构造函数、析构函数和赋值函数,已知类String 的原型为: class String { public: String(const char *str = NULL); // 普通...
  • 本文重点:应该为多态基类声明虚析构器。一旦一个类包含虚函数,它就应该包含一个虚析构器。如果一个类不用作基类或者不需具有多态性,便不应该为它声明虚析构器。
  • 析构函数用于析构类的实例。 备注 不能在结构中定义析构函数。只能对类使用析构函数。 一个类只能有一个析构函数。 无法继承或重载析构函数。 无法调用析构函数。它们是被自动调用的。 析构函数既没有修饰符,也没有...
  • 主要介绍了C++ 析构函数与变量的生存周期实例详解的相关资料
  • 本篇文章是对c++中默认析构函数的使用进行了详细的分析介绍。需要的朋友参考下
  • 主要介绍了详解C++中如何将构造函数或析构函数的访问权限定为private的方法,文中还解释了构造函数与虚函数的区别,需要的朋友可以参考下
  • 构造函数与析构函数

    2016-02-16 14:46:56
    每个类都具有构造函数和析构函数。其中,构造函数在定义对象时被调用,析构函数在...析构函数没有返回值,甚至void类型也不可以,析构函数也没有参数,因此析构函数是不能够重载的。这是析构函数与普通函数最大的区别。
  • 即C++ 的全局对象构造函数在main 函数之前执行,而C++ 全局对象的析构函数在main函数之后被执行。  Linux系统中,一般程序的入口是“ _start , 这个函数是Linux系统库(Glibc)的一部分。当我们的程序与Glibc库链接...
  • 析构函数

    千次阅读 2021-01-17 17:48:57
    析构函数也是一个在类中跟构造函数类似的特殊功能的成员函数,作用与构造函数相反,是在对象的声明周期结束的时候会被自动调用.在C++中析构函数的名字跟类名相同,并在前面带上一个取反的符号~,表达的意思也跟构造...

    析构函数也是一个在类中跟构造函数类似的特殊功能的成员函数,作用与构造函数相反,是在对象的声明周期结束的时候会被自动调用.在C++中析构函数的名字跟类名相同,并在前面带上一个取反的符号~,表达的意思也跟构造函数的过程相反.

    默认情况下,如果类没有定义自己的析构函数,编译器会自动为该类生成一个默认的析构函数,只不过函数体是空的,也就是什么都没做.所有,如果需要在对象被删除的时候做一些操作的话,就得自己定义析构函数.


    以下几种情况会自动调用析构函数:
    ①如果一个函数中定义了一个局部变量的对象,那么当这个函数执行结束时也就是该变量对象生命周期结束的时候,所以析构函数会被自动调用.
    ②全局变量或者static类型的变量,他们的生命周期一般是在程序退出的时候,该对象的析构函数才会被调用.
    ③如果是用new操作符动态的创建了一个对象,只有当用delete进行释放该对象的时候,析构函数才会被调用.


    析构函数的作用:
    那构造函数来说,构造函数是新建对象吗?不是,而是在对象被创建出来后自动被调用的,用来初始化相关信息的函数.同理:析构函数也不是用来删除对象的,而是当对象被删除的时候自动被调用的,用来做一些对象被删除之前的清理工作,只有对象的生命周期结束,那么程序就自动执行析构函数来完成这个工作.


    析构函数的特点:
    析构函数不返回任何值,没有函数类型,也没有任何函数的参数.析构函数不能被重载,所以,一个类中可以有多个构造函数,但只有一个析构函数.


    析构函数使用示例:

    CStudent::~CStudnet()
    {
    	cout<<"~CStudent() callec."<<endl;
    }
    

    //本文来源于VC驿站,仅作为个人学习记录

    展开全文
  • 析构函数__del__定义:在类里定义,如果不定义,Python 会在后台提供默认析构函数析构函数__del__调用: A、使用del 显式的调用析构函数删除对象时:del对象名;  class Foo: def __init__(self,x): self.x=x ...
  • 本篇文章是对C++中虚析构函数的作用进行了详细的分析介绍,需要的朋友参考下
  • 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;

    在这里插入图片描述

    展开全文
  • //析构函数做成员函数 }; Base::~Base()//成员函数实现 { cout; } class Derived:public Base { public: Derived(); ~Derived(); private: int *p; }; Derived::Derived() { p=new int(0);//从堆上分配一个int型...
  • C++析构函数不能抛出异常的几条原因,里面详细列出
  • 本文详细对比了C#中析构函数、Dispose和Close方法的区别,三者都是释放资源,本文介绍了他们各自的使用方法和使用场景,希望对大家有所帮助。
  • 主要介绍了C++编程中派生类的析构函数,析构函数平时一般使用较少,需要的朋友可以参考下
  • 详细解释了为什么析构函数可以是虚函数,而构造函数不能是虚函数
  • 今天我们来谈一谈面试 C++ 工程师时经常被谈到的一个问题:为什么析构函数必须是虚函数?为什么默认的析构函数不是虚函数? 首先,我们看一下百度百科对虚函数是怎么定义的: 在某基类中声明为 virtual并在一个或多个...

    微信搜索“编程笔记本”,获取更多信息
    ------------- codingbook2020 -------------

    今天我们来谈一谈面试 C++ 工程师时经常被谈到的一个问题:为什么析构函数必须是虚函数?为什么默认的析构函数不是虚函数?

    首先,我们看一下百度百科对虚函数是怎么定义的:

    在某基类中声明为 virtual并在一个或多个派生类中被重新定义的成员函数,用法格式为:virtual 函数返回类型 函数名 ( 参数表 ) { 函数体 };实现多态性,通过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数。

    好了,现在我们大概知道什么是虚函数,虚函数就是类中使用关键 virtual修饰的成员函数,其目的是为了实现多态性。

    那么什么是多态性呢?

    所谓多态性,顾名思义就是“多个性态”。更具体一点的就是,用一个名字定义多个函数,这些函数执行不同但相似的工作。最简单的多态性的实现方式就是函数重载模板,这两种属于静态多态性。还有一种是动态多态性,其实现方式就是我们今天要说的虚函数

    回归正题。

    一、为什么析构函数必须是虚函数?

    当然了,这么说其实是不太严谨的,因为我完全可以将析构函数定义成非虚函数。这个我们后面再说。

    首先我们需要知道析构函数的作用是什么。析构函数是进行类的清理工作,具体来说就是释放构造函数开辟的内存空间和资源,当然我们完全可以在析构函数中进行任何我们想要的操作,比如下面我们给出的示例代码,就在析构函数中打印提示信息。

    前面我们在介绍虚函数的时候就说到,为实现多态性,可以通过基类的指针或引用访问派生类的成员。也就是说,声明一个基类指针,这个基类指针可以指向派生类对象

    下面我们来看一个例子:

    #include <iostream>
    
    using namespace std;
    
    class Father {
    public:
        ~Father() {
            cout << "class Father destroyed" << endl;
        }
    };
    
    class Son : public Father {
    public:
        ~Son() {
            cout << "class Son destroyed" << endl;
        }
    };
    
    int main() {
        Father* p = new Son;
        delete p;
    
        return 0;
    }
    
    /*
    运行结果:
    class Father destroyed
    */
    

    上面的示例程序中,我们定义了两个类,一个基类,一个派生类,派生类公有继承父类。为了描述简单,这两个类只定义了析构函数,并在析构函数中输出提示信息。在主函数中,我们声明了一个基类的指针,并用一个派生类的实例去初始化这个基类指针,随后删除这个指针。我们看到程序运行的结果,只有基类的析构函数被调用。

    为什么会这样呢?指针明明指向的是派生类对象,那删除这个指针,为何只有基类的析构函数被调用,而派生类的析构函数却没有调用呢?

    我们先把问题留在这里,接下来我们看看,若析构函数被定义成虚函数会怎么样呢?

    #include <iostream>
    
    using namespace std;
    
    class Father {
    public:
        virtual ~Father() {
            cout << "class Father destroyed" << endl;
        }
    };
    
    class Son : public Father {
    public:
        ~Son() {
            cout << "class Son destroyed" << endl;
        }
    };
    
    int main() {
        Father* p = new Son;
        delete p;
    
        return 0;
    }
    
    /*
    运行结果:
    class Son destroyed
    class Father destroyed
    */
    

    当基类的析构函数被定义成虚函数时,我们再来删除这个指针时,先调用派生类的析构函数,再调用基类的析构函数,很明显这才是我们想要的结果。因为指针指向的是一个派生类实例,我们销毁这个实例时,肯定是希望即清理派生类自己的资源,同时又清理从基类继承过来的资源。而当基类的析构函数为非虚函数时,删除一个基类指针指向的派生类实例时,只清理了派生类从基类继承过来的资源,而派生类自己独有的资源却没有被清理,这显然不是我们希望的。

    所以说,如果一个类会被其他类继承,那么我们有必要将被继承的类(基类)的析构函数定义成虚函数。这样,释放基类指针指向的派生类实例时,清理工作才能全面进行,才不会发生内存泄漏。

    二、为什么默认的析构函数不是虚函数?

    那么既然基类的析构函数如此有必要被定义成虚函数,为何类的默认析构函数却是非虚函数呢?

    首先一点,语言设计者如此设计,肯定是有道理的。

    原来是因为,虚函数不同于普通成员函数,当类中有虚成员函数时,类会自动进行一些额外工作。这些额外的工作包括生成虚函数表虚表指针,虚表指针指向虚函数表。每个类都有自己的虚函数表,虚函数表的作用就是保存本类中虚函数的地址,我们可以把虚函数表形象地看成一个数组,这个数组的每个元素存放的就是各个虚函数的地址。
    这样一来,就会占用额外的内存,当们定义的类不被其他类继承时,这种内存开销无疑是浪费的。

    这样一说,问题就不言而喻了。当我们创建一个类时,系统默认我们不会将该类作为基类,所以就将默认的析构函数定义成非虚函数,这样就不会占用额外的内存空间。同时,系统也相信程序开发者在定义一个基类时,会显示地将基类的析构函数定义成虚函数,此时该类才会维护虚函数表和虚表指针。

    这个问题至此就解释完成了,祝大家面试顺利!

    识别下方二维码关注我,或微信搜索**“编程笔记本”**,获取更多信息。

    展开全文
  • 析构函数.cpp

    2019-10-20 20:18:15
    面向对象程序设计,即C++语言,类。析构函数,文件里面有详细的注释。
  • 构造函数不能声明为虚函数,析构函数可以声明为虚函数。
  • (3)若用户没有自定义析构函数,编译器会默认自动生成一个缺省析构函数,即使用户自定义析构函数,在底层编译器依然会在自定义析构函数的基础上再次调用默认析构函数 (4)如果一个类中定义有指针,且在使用的过程...

    C++析构函数

    (1)对于析构函数:析构函数与构造函数相呼应,从调用构造函数开始到自动执行析构函数二者调用期间即为所创建对象实例的生命周期。

    (2)析构函数与类名相同,仅前面加一个~,一般析构函数无参,且无返回值,析构函数具有唯一性,不可重载

    (3)若用户没有自定义析构函数,编译器会默认自动生成一个缺省析构函数,即使用户自定义析构函数,在底层编译器依然会在自定义析构函数的基础上再次调用默认析构函数

    (4)如果一个类中定义有指针,且在使用的过程中动态申请了内存空间,一般建议在调用析构函数前显式释放内存空间,避免内存泄漏

    (5)含有继承关系的类析构的顺序:派生类析构函数->对象成员析构函数->基类析构函数

    虚析构函数

    一般面试中最容易被问到:析构函数能不能写成虚函数???

    判断一个成员方法/函数能不能实现虚函数,需要满足以下两点:

    1. 对象已存在
    2. 函数得有地址

    析构函数在调用时,对象是已经存在的。对于构造函数,inline成员函数,static成员函数调用时对象还没有被创建,因此这三个函数无法定义为virtual函数

    析构函数在调用时,对象是已经存在的且对象的前4个字节存放虚函数指针,而虚函数指针记录虚函数表地址,通过虚函数表可以找到虚析构函数的地址

    析构函数是不是一定要写成虚函数??什么时候必须写成虚函数??

    当使用基类指针指向new开辟出的派生类对象:

    class Base
    {
    
    };
    class Child:public Base
    {
    
    };
    
    
    Base *ptr=new Child();
    delete ptr;

    当使用delete释放资源时,只会调用基类默认析构函数,而不会调用派生类析构函数,如果派生类中有指针成员且开辟内存空间,如果不显示释放内存空间,通过析构无法释放,此时也无法释放派生类资源,造成资源泄漏

    如果将其声明为虚析构函数,基类指针指向派生类对象,析构时会先调用派生类析构函数再调用基类析构函数完成资源释放

    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 183,466
精华内容 73,386
关键字:

析构函数