精华内容
下载资源
问答
  • 析构函数详解

    千次阅读 多人点赞 2020-08-05 20:36:16
    析构函数详解 析构函数的概念 前面通过构造函数的学习,我们知道一个对象是怎么来的,那一个对象又是怎么没呢的? 析构函数:与构造函数功能相反,析构函数是完成对象的销毁,局部对象销毁工作是由编译器完成的。而...

    析构函数详解

    析构函数的概念
    • 前面通过构造函数的学习,我们知道一个对象是怎么来的,那一个对象又是怎么没呢的?
    • 析构函数:与构造函数功能相反,析构函数是完成对象的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成类的一些资源清理工作。
    • 析构函数用来完成对象资源清理的工作
    析构函数的特性
    • 析构函数名是在类名前加上字符 ~。
    • 无参数无返回值。
    • 一个类有且只有一个析构函数。若用户没有显式定义,系统会自动生成默认的析构函数。
    • 当对象生命周期结束时,C++编译系统系统会自动调用析构函数
    • 下面是通过C++的类,来封装顺序表
    #include<iostream>
    #include<assert.h>
    using namespace std;
    
    class SeqList
    {
    public:
    	SeqList(int capacity = 10)
    	{
    		array = (int*)malloc(sizeof(int) * capacity);
    		assert(array);
    		_capacity = capacity;
    		_size = 0;
    	}
    private:
    	int* array;
    	int _size;
    	int _capacity;
    };
    void TestSeqList()
    {
    	SeqList s;
    }
    int main()
    {
    	SeqList s(100);
    
    	return 0;
    }
    
    但是上面的代码存在有很大的问题,就是代码中所创建的变量并没有被销毁和释放,用析构函数来清理资源
    • 在这种情况下,我们需要使用析构函数来完成对象资源的销毁工作。
    #include<iostream>
    #include<assert.h>
    using namespace std;
    
    class SeqList
    {
    public:
    	SeqList(int capacity = 10)
    	{
    		cout << "SeqList(int):" << this << endl;
    		array = (int*)malloc(sizeof(int) * capacity);
    		assert(array);
    		_capacity = capacity;
    		_size = 0;
    	}
    
    	//析构函数
    	~SeqList()
    	{
    		if (array)
    		{
    			free(array);
    			_capacity = 0;
    			_size = 0;
    		}
    		cout << "~SeqList():" << this << endl;
    	}
    private:
    	int* array;
    	int _size;
    	int _capacity;
    };
    void TestSeqList()
    {
    	SeqList s;
    }
    int main()
    {
    	SeqList s(100);
    
    	return 0;
    }
    
    析构函数不能重载
    • 析构函数没有参数,所以析构函数无法重载,都没有参数,怎么重载
    关于编译器自动生成的析构函数,是否会完成一些事情呢?下面的程序我们会看到,编译器生成的默认析构函数,对会自定类型成员调用它的析构函数
    #include<iostream>
    #include<string.h>
    using namespace std;
    class String
    {
    public:
    	String(const char* str = "jack")
    	{
    		_str = (char*)malloc(strlen(str) + 1);
    		strcpy(_str, str);
    	}
    	~String()
    	{
    		cout << "~String()" << endl;
    		free(_str);
    	}
    private:
    	char* _str;
    };
    class Person
    {
    private:
    	String _name;
    	int _age;
    };
    int main()
    {
    	Person p;
    	return 0;
    }
    
    编译器也会生成默认的析构函数

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • 代码如下:#include class base{public:  base() { std::cout<<std::endl; std::cout<<“base constructor”<<std::endl; func1(); std::cout<<std::endl; } ... func
  • 要求有构造函数、析构函数,完成赋值、显示、计算矩形的面积等接口,并编写main函数进行测试。 class Rect {public: int Area_int(); Rect(int l, int w); ~Rect(); private: int nLength; int nWidth; }; 2...
  • a.h class A {  public: ~A(); }; c.cpp A::~A() { ... }

    a.h

    class A {

     public:

    ~A();

    };

    c.cpp

    A::~A() {

    ...

    }

    展开全文
  • //析构函数做成员函数 }; Base::~Base()//成员函数实现 { cout; } class Derived:public Base { public: Derived(); ~Derived(); private: int *p; }; Derived::Derived() { p=new int(0);//从堆上分配一个int型...
  • 这篇文章用于总结当析构函数是普通析构函数、虚析构函数、纯虚析构函数时,我们使用delete运算符删除一个指针对象时,析构函数会有什么情况发生;普通析构函数CBase是基类,CDerive是其子类,类源码代码如下:class ...

    我们知道对象在结束其生命周期之前,都会调用析构函数以完成必要的清理工作;派生类调用的析构函数顺序是“先子类,后基类”; 这篇文章用于总结当析构函数是普通析构函数、虚析构函数、纯虚析构函数时,我们使用delete运算符删除一个指针对象时,析构函数会有什么情况发生

    ####普通析构函数####

    CBase是基类,CDerive是其子类,类源码代码如下:

    class CBase
    {
    public:
        CBase(){}
        //基类析构函数
        ~CBase(){ cout << "CBase Destructor" << endl; } 
    private:
        int a;
    };
    
    class CDerive:public CBase
    {
    public:
        CDerive(){}   
        //子类析构函数
        ~CDerive(){ cout << "CDerive Destructor" << endl; }
    private:
        int b;
    };
    

    测试代码如下:

    //case1
    CDerive *pDeriveObj = new CDerive();
    delete pDeriveObj;
    
    //case2
    //基类指针对象可以指向派生类,体现基类和派生类赋值兼容关系(不同类型可以转化和赋值),
    //但是pBaseObj只能访问基类成员,不能访问派生类成员
    CBase* pBaseObj = new CDerive();
    delete pBaseObj; //等价于删除基类对象
    

    测试结果:

    /* case 1
    先析构子类:CDerive Destructor
    后析构基类:CBase Destructor
    */
    
    /* case2
    仅析构基类:CBase Destructor
    */
    

    总结:

    1. 若delete运算符删除的是子类指针对象,则会调用子类和基类的析构函数;
    2. 若析构函数是非虚的,即使基类指针指向的是子类对象,则delete 指针对象时,也仅调用基类的析构函数

    ####虚析构函数####

    当基类中的析构函数设置为虚函数时,我们在delete 基类指针对象时,能根据实际类型完成对象的清理工作;源码如下:

    class CBase
    {
    public:
        CBase(){}
        //基类虚析构函数
        virtual ~CBase(){ cout << "CBase Destructor" << endl; } 
    private:
        int a;
    };
    
    class CDerive:public CBase
    {
    public:
        CDerive(){}   
        //子类虚析构函数
        virtual ~CDerive(){ cout << "CDerive Destructor" << endl; }
    private:
        int b;
    };
    

    测试代码:

     //指向基类对象
     CBase*pBaseObj_case1 = new CBase();
     delete pBaseObj_case1;
     
     //指向子类对象
     CBase*pBaseObj_case2 = new CDerive();
     delete pBaseObj_case2;
    

    运行结果:
    //case1
    CBase Destructor

    //case2
    CDerive Destructor ->先子类
    CBase Destructor ->后基类

    总结:
    当基类的析构函数为虚函数时,基类指针指向的是子类对象时,使用delete运算符删除指针对象,析构函能够按照“先子类,后基类”的原则完成对象清理;这样在多重继承的类中,能够保证每个类都能够得到正确的清理;比如基类和子类的缓冲区都能被释放;

    ####纯虚析构函数####

    当基类中有纯虚函数时,基类是不能被实例化的,需要在子类中重写该纯虚函数;对于纯虚析构函数有点特殊,源码如下:

    class CBase
    {
    public:
        CBase(){}
        //基类析构函数
        virtual ~CBase()= 0;
    private:
        int a;
    };
    
    class CDerive:public CBase
    {
    public:
        CDerive(){}   
        //子类析构函数
        virtual ~CDerive(){ cout << "CDerive Destructor" << endl; }
    private:
        int b;
    };
    

    测试代码:

    CBase*pBaseObj = new CDerive();
    delete pBaseObj;
    

    当我们编译代码时,会发现代码编译不过提示:
    “error LNK2019: 无法解析的外部符号 “public: virtual __thiscall CBase::~CBase(void)” (??1CBase@@UAE@XZ),该符号在函数 “public: virtual __thiscall CDerive::~CDerive(void)” (??1CDerive@@UAE@XZ) 中被引用”

    原因是子类析构时需要调用基类的析构函数,但发现代码中没有实现CBase析构函数,导致编译异常;
    解决办法就是我们在CBase类外实现其函数体,而不是在子类中重写,而且~CDerive函数也是虚函数,即使其函数名不同;这就是和其他纯虚函数有特殊的地方;

    我们需要在CBase类外增加如下的析构函数:

    CBase::~CBase()
    { 
        cout << "CBase Destructor" << endl; 
    } 
    

    这样得到的运行结果是:
    CDerive Destructor ->先子类
    CBase Destructor ->后基类

    ####总结####

    最好把基类的析构函数声明为虚函数。这将使所有派生类的析构函数自动成为虚函数。这样,如果程序中显式地用了delete运算符准备删除一个对象,而delete运算符的操作对象用了指向派生类对象的基类指针,则系统会调用相应类的析构函数。

    专业人员一般都习惯声明虚析构函数,即使基类并不需要析构函数,也显式地定义一个函数体为空的虚析构函数,以保证在撤销动态分配空间时能得到正确的处理。

    参考资料:

    http://c.biancheng.net/cpp/biancheng/view/247.html

    http://blog.csdn.net/yapian8/article/details/46418687

    展开全文
  • 析构函数实现原理

    千次阅读 2016-10-14 22:28:11
    析构函数的理论前提是执行完子类的析构函数,那么父类的虚构函数必然会被执行。那么当用delete释放一个父类指针所实例化的子类对象时,如果没有定义析构函数,那么将只会调用父类的析构函数,而不会调用子类的虚构...

    虚析构函数的理论前提是

    执行完子类的析构函数,那么父类的虚构函数必然会被执行。

    那么当用delete释放一个父类指针所实例化的子类对象时,如果没有定义虚析构函数,那么将只会调用父类的析构函数,而不会调用子类的虚构函数,导致内存的泄漏。

    Class Shape
    {
    public:
        virtual Shape();
        ~Shape();
    private:
        int m_ir;
    };
    
    Class Circle:public Shape
    {
    public:
        Circle();
        ~Circle();
    private:
        int m_ir;
    };
    
    int main()
    {
        Shape *shape=new Circle;
        delete shape;
        shape=NULL;
    }

    如果基类中定义了虚析构函数,那么在Shape的虚函数表中就会存放虚析构函数的地址

    这里写图片描述
    而编译器会自动帮派生类的析构函数前加上virtual关键字。
    那么实例化Circle时,在Circle的虚函数表中也会存放Circle的虚析构函数的地址。在执行delete shape时,在Circle的虚函数表中找到虚析构函数的地址,执行析构函数,释放派生类占用的内存,而派生类的析构函数被调用那么基类的析构函数也会自动被调用。
    这里写图片描述

    展开全文
  • 纯虚函数是是一种特殊的虚函数,可以说是虚函数的子集,它可以不需要再基类中写函数实现,而虚函数不写函数实现就会报错。 为啥会有虚函数? 为了方便实用多态,编程者常常需要在基类中定义虚函数。在很多情况下,...
  • 今天我们来谈一谈面试 C++ 工程师时经常被谈到的一个问题:为什么析构函数必须是虚函数?为什么默认的析构函数不是虚函数? 首先,我们看一下百度百科对虚函数是怎么定义的: 在某基类中声明为 virtual并在一个或多个...
  • Java是否有析构函数

    2021-03-15 00:00:22
    Java是否有析构函数? 我似乎无法在此找到任何文档。 如果没有,我怎么能达到同样的效果?为了使我的问题更具体,我正在编写一个处理数据的应用程序,规范中说应该有一个“重置”按钮,以将应用程序恢复到其最初的...
  • 将可能会被继承的父类的析构函数设置为虚函数,可以保证当我们new一个子类,然后使用基类指针指向该子类对象,释放基类指针时可以释放掉子类的空间,防止内存泄漏。 C++默认的***析构函数不是虚函数是因为虚函数需要...
  • 文章目录一、构造函数1、构造函数的概念2、构造函数的定义3、默认构造函数与有参构造函数4、静态构造函数5、静态构造函数和实例构造函数的使用二、析构函数三、构造函数与析构函数区别 一、构造函数 首先,我们要...
  • 通过下面的代码来说明: #include #include #include using namespace std; /**  * 定义动物类:Animal  * 成员函数:eat()、move()  */ class Animal { public:  // 构造函数 ... // 析构函数  vi
  • C++实验四——构造函数与析构函数 (1) 定义一个正方形类,该类包括:正方形的边长(取值范围为1-30个“*”),四个成员函数,分别为:取边长、设置边长、画正方形和在构造这些类对象时能初始化正方形边长。 编写主函数...
  • C++中基类的析构函数为什么要用virtual虚析构函数

    万次阅读 多人点赞 2018-08-11 15:53:07
    大家知道,析构函数是为了在对象不被使用之后释放它的资源,虚函数是为了实现多态。那么把析构函数声明为vitual有什么作用呢?直接的讲,C++中基类采用virtual虚析构函数是为了防止内存泄漏。具体地说,如果派生类中...
  • 通常我们在写一个基类的时候,若基类成员变量需要动态申请内存空间或基类成员变量引用了系统资源时,需定义类的析构函数来明确在删除对象时需要释放的成员。 1. 析构函数 析构函数在析构时调用。若在堆上申请的内存...
  • 众所周知,在实现多态的过程中,一般将基类的析构函数设为virtual,以便在delete的时候能够多态的链式调用。那么析构函数是否可以设为纯虚呢? class CBase { public: CBase() { printf("CBase()\n"); } ...
  • 为什么父类析构函数必须为虚函数

    千次阅读 2020-12-14 22:21:14
    1、如果父类的析构函数不是虚函数,则不会触发动态绑定(多态),结果就是只会调用父类的析构函数,而不会调用子类的析构函数,从而可能导致子类的内存泄漏(如果子类析构函数中存在free delete 等释放内存操作时)...
  • 纯虚函数可以有实现:唯一麻烦就是必须在类的定义之外(cpp文件)实现它。 申明一个函数为纯虚并不意味着它没有实现,它意味着: 当前类是抽象类 ; 任何从此类派生的实体类必须将此函数申明为一个“普通”的虚函数...
  • 在Java、C#中有关键词abstract指明抽象函数、抽象类,但是在C++中没有这个关键词,很显然,在C++也会需要只需要在基类声明某函数的情况,而不需要写具体的实现,那C++中是如何实现这一功能的,答案是纯虚函数。...
  • 析构函数为虚函数

    千次阅读 2019-06-20 12:37:14
    转载 ... 多态是面向对象的一个基本属性,包括静态多态(编译阶段)和动态多态(运行阶段),静态多态主要是指函数参数不同产生的多态性...可以通过基类指针直接调用派生类的对象函数,当然这种多态是通过虚函数实...
  • 对于虚析构函数的理解

    万次阅读 多人点赞 2017-08-06 16:09:00
    首先,对于虚析构函数,那就得说下构造函数和析构函数了。 构造函数:进行初始化成员变量的函数。 析构函数:在对象生命周期结束的时候,完成资源的回收和清理。 对于虚析构,就是在析构函数前加virtual关键字,那么...
  • 大家先了解下什么是构造函数,什么是析构函数,作用是什么? 构造函数(方法)是对象创建完成后第一个被对象自动调用的方法。它存在于每个声明的类中,是一个特殊的成员方法。作用是执行一些初始化的任务。Php中使用...
  • C++中虚析构函数和纯虚函数的作用

    千次阅读 多人点赞 2017-12-26 23:38:10
    析构函数为了能够正确的调用对象的析构函数,一般要求具有层次结构的顶级类定义其析构函数为虚函数。因为在delete一个抽象类指针时候,必须要通过虚函数找到真正的析构函数。class Base { public: Base(){} ...
  • C#析构函数

    千次阅读 2017-01-11 19:04:36
    析构函数用于析构类的实例。 备注 不能在结构中定义析构函数。只能对类使用析构函数。 一个类只能有一个析构函数。 无法继承或重载析构函数。 无法调用析构函数。它们是被自动调用的。 析构函数既...
  • 一. 构造函数1. 构造函数的简单介绍 构造函数是一种特使的方法。主要用来在创建对象时初始化对象,即对对象的成员变量赋值。当成员变量是私有的时候,要对...(3)对象构造时(对象实例化时)系统自动调用对应的...
  • 析构函数的定义

    万次阅读 2017-12-07 22:02:33
    1.析构函数的定义 析构函数:当对象脱离其作用域时(例如对象所在的函数已调用完毕),系统会自动执行析构函数析构函数往往用来做“清理善后”的工作(例如在建立对象时用new开辟了一段内存空间,则在该对象消亡...
  • 将可能会被继承的父类的析构函数设置为虚函数,可以保证当我们new一个子类,然后使用基类指针指向该子类对象,释放基类指针时可以释放掉子类的空间,防止内存泄漏。 C++默认的***析构函数不是虚函数是因为虚函数...
  • 类的析构函数调用方式堆和栈结论系统在什么情况下不会自动调用析构函数呢?举例参考 堆和栈 为了理解这个问题,我们必须首先弄明白“堆”和“栈”的概念。 堆区(heap) —— 一般由程序员分配释放, 若程序员不...
  • 析构函数

    2018-06-08 09:50:18
    实话说,我还不懂什么是析构函数,以及它是怎样实现的看起来很高级的样子构造函数和析构函数自动执行析构函数在最后执行浅谈 “析构函数”c++中析构函数c++中析构函数(2)...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 120,946
精华内容 48,378
关键字:

析构函数的实现