精华内容
下载资源
问答
  • 1.每个析构函数(不加 virtual) 只负责清除自己的成员。 2.可能有基类指针,指向的确是派生成员的情况。(这是很正常的), 那么当析构一个指向派生成员的基类指针时,程序就不知道怎么办了。 所以要保证运行...
    首先要明确:

    1.每个析构函数(不加 virtual) 只负责清除自己的成员。
    2.可能有基类指针,指向的确是派生类成员的情况。(这是很正常的),
       那么当析构一个指向派生类成员的基类指针时,程序就不知道怎么办了。 
       所以要保证运行适当的析构函数,基类中的析构函数必须为虚析构。

       基类指针可以指向派生类的对象(多态性),如果删除该指针delete []p;就会调用该指针指向的派生类析构函数,而派生类的析构函数又自动调用基类的析构函数,这样整个派生类的对象完全被释放。如果析构函数不被声明成虚函数,则编译器实施静态绑定,在删除基类指针时,只会调用基类的析构函数而不调用派生类析构函数,这样就会造成派生类对象析构不完全。所以,将析构函数声明为虚函数是十分必要的。

     

    示例代码:

    1.第一段代码

    #include
    using namespace std;
    class ClxBase{
    public:
    ClxBase() {};
    ~ClxBase() {cout << "Output from the destructor of class ClxBase!" << endl;};

    void DoSomething() { cout << "Do something in class ClxBase!" << endl; };
    };

    class ClxDerived : public ClxBase{
    public:
    ClxDerived() {};
    ~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; };

    void DoSomething() { cout << "Do something in class ClxDerived!" << endl; };
    };
    int main(){ 
    ClxDerived *p = new ClxDerived;
    p->DoSomething();
    delete p;
    return 0;
    }

    运行结果:

    Do something in class ClxDerived!

    Output from the destructor of class ClxDerived!

    Output from the destructor of class ClxBase!

    这段代码中基类的析构函数不是虚函数,在main函数中用继承类的指针去操作继承类的成员,释放指针P的过程是:先释放继承类的资源,再释放基类资源.


    2.第二段代码

    #include
    using namespace std;
    class ClxBase{
    public:
    ClxBase() {};
    ~ClxBase() {cout << "Output from the destructor of class ClxBase!" << endl;};

    void DoSomething() { cout << "Do something in class ClxBase!" << endl; };
    };

    class ClxDerived : public ClxBase{
    public:
    ClxDerived() {};
    ~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; };

    void DoSomething() { cout << "Do something in class ClxDerived!" << endl; }
    };
    int main(){ 
    ClxBase *p = new ClxDerived;
    p->DoSomething();
    delete p;
    return 0;
    }

    输出结果:

    Do something in class ClxBase!
    Output from the destructor of class ClxBase!

    这段代码中基类的析构函数同样不是虚函数,不同的是在main函数中用基类的指针去操作继承类的成员,释放指针P的过程是:只是释放了基类的资源,而没有调用继承类的析构函数.调用dosomething()函数执行的也是基类定义的函数.

    一般情况下,这样的删除只能够删除基类对象,而不能删除子类对象,形成了删除一半形象,造成内存泄漏.

    在公有继承中,基类对派生类及其对象的操作,只能影响到那些从基类继承下来的成员.如果想要用基类对非继承成员进行操作,则要把基类的这个函数定义为虚函数.

    析构函数自然也应该如此:如果它想析构子类中的重新定义或新的成员及对象,当然也应该声明为虚的.


    3.第三段代码:

    #include
    using namespace std;
    class ClxBase{
    public:
    ClxBase() {};
    virtual ~ClxBase() {cout << "Output from the destructor of class ClxBase!" << endl;};
    virtual void DoSomething() { cout << "Do something in class ClxBase!" << endl; };
    };

    class ClxDerived : public ClxBase{
    public:
    ClxDerived() {};
    ~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; };
    void DoSomething() { cout << "Do something in class ClxDerived!" << endl; };
    };

    int main(){ 
    ClxBase *p = new ClxDerived;
    p->DoSomething();
    delete p;
    return 0;
    }

    运行结果:

    Do something in class ClxDerived!
    Output from the destructor of class ClxDerived!
    Output from the destructor of class ClxBase!

    这段代码中基类的析构函数被定义为虚函数,在main函数中用基类的指针去操作继承类的成员,释放指针P的过程是:只是释放了继承类的资源,再调用基类的析构函数.调用dosomething()函数执行的也是继承类定义的函数.


    如果不需要基类对派生类及对象进行操作,则不能定义虚函数,因为这样会增加内存开销.当类里面有定义虚函数的时候,编译器会给类添加一个虚函数表,里面来存放虚函数指针,这样就会增加类的存储空间.所以,只有当一个类被用来作为基类的时候,才把析构函数写成虚函数.

    转载于:https://www.cnblogs.com/dreamsyeah/p/5878371.html

    展开全文
  • 析构函数

    2021-03-11 12:20:57
    析构函数的定义 析构函数: 当对象脱离其作用域时(例如对象所在的函数已调用完毕),系统会自动执行析构函数。析构函数往往用来做...换言之,一个类可以多个构造函数,但是只能有一个析构函数 何时调用析构函数

    析构函数的定义

    析构函数: 当对象脱离其作用域时(例如对象所在的函数已调用完毕),系统会自动执行析构函数。析构函数往往用来做“清理善后”的工作 (例如在建立对象时用new开辟了一段内存空间,则在该对象消亡前应在析构函数中用delete释放这段存储空间)

    C++规定析构函数是类名前面加一个波浪号(~)。其定义形式为:

    ~类名() {
    	函数体
    }
    

    析构函数不返回任何值,没有返回类型,也没有函数参数。由于没有函数参数,因此它不能被重载。换言之,一个类可以有多个构造函数,但是只能有一个析构函数

    何时调用析构函数:
    (1)对象在程序运行超出其作用域时自动撤销,撤销时自动调用该对象的析构函数。如函数中的非静态局部对象
    (2)如果new运算动态地建立了一个对象,那么用delete运算释放该对象时,调用该对象的析构函数

    析构函数举例:

    #include<iostream>
    #include<string.h>
    using namespace std;
    
    class Point {
    	public:
    		Point(int a,int b) : x(a),y(b) { } //带参数的构造函数
    		~Point() { //析构函数
    			cout<<"析构函数被调用。"<<endl; }
    		void show() { cout<<x<<","<<y<<endl;
    	private:
    		int x,y;
    };
    
    int main()
    {
    	Point pt1(10,20);
    	pt1.show();
    	return 0;
    }		
    

    合成析构函数

    与复制构造函数不同,编译器总是会为类生成一个析构函数,称为合成析构函数(synthesized destructor)

    合成析构函数按对象创建时的逆序撤销每个非静态成员,即它是按成员在类中声明次序的逆序撤销成员的。对于类类型的每个成员,合成析构函数调用该成员的析构函数来撤销对象

    需要注意,合成析构函数并不删除指针成员所指向的对象,它需要程序员显式编写析构函数去处理

    何时需要编写析构函数

    许多类不需要显式地编写析构函数,尤其是具有构造函数的类不一定需要定义自己的析构函数。析构函数通常用于释放在构造函数或在对象生命期内获取的资源(如动态分配的内存)

    但是,析构函数的作用并不仅限于释放资源方面,它可以包含任意操作,用来执行”对象即将被撤销之前程序员所期待的任何操作“。

    如果类需要析构函数,则该类几乎需要定义自己的复制构造函数和赋值运算符重载,这个规则称为析构函数三法制

    析构函数举例:

    #include<iostream>
    using namespace std;
    
    class CString { //CString类
    	public:
    		Cstring(const char *str); //单个参数构造函数
    		void show() { cout<<p<<endl; }
    	private:
    		char *p; //存储字符串动态内存区
    };
    
    CString::Cstring(const char *str) {
    	p = new char[strlen(str)+1]; //为存储str动态分配内存
    	strcpy(p,str); //复制str到p
    	cout<<"构造:"<<str<<endl;
    }
    
    CString::~CString() {
    	cout<<"析构:"<<p<<endl;
    	delete []p;
    }
    
    int main()
    {
    	CString s1("C++"),s2="JavaScript";
    	s1.show();
    	s2.show();
    	return 0;
    }
    

    运行结果:
    构造:C++
    构造:JavaScript
    C++
    JavaScript
    析构:JavaScript
    析构:C++

    析构函数和析构函数的调用次序

    在使用构造函数和析构函数时,需要特别注意对它们的调用时间和调用次序

    构造函数和析构函数的调用很像一个栈的先进后出,调用析构函数的次序正好与调用构造函数的次序相反。最先被调用的构造函数,其对应的(同一对象中的)析构函数最后被调用,而最后被调用的构造函数,其对应的析构函数最先被调用

    可简述为:先构造的后析构,后构造的先析构

    展开全文
  • 析构函数与合成析构函数

    千次阅读 2012-02-28 16:37:33
    今天看《c++ primer》的时候,突然看到合成析构函数这个名词,对析构函数了解的多点,对合成析构函数则了解的不析构函数特点: 1.整个只有一个,即不能重载; 2.没有形参; 3.没有返回值; 4.不能被继承...

    今天看《c++ primer》的时候,突然看到合成析构函数这个名词,对析构函数了解的多点,对合成析构函数则了解的不多。

    析构函数特点:

    1.整个类只有一个,即不能重载;

    2.没有形参;

    3.没有返回值;

    4.不能被继承(继承的是成员变量和成员函数,个人理解严格说这些构造函数,析构函数不能称之为“函数”,因为不符合函数定义的特征,所以构造函数,析构函数不能被继承)

    5.可以手动调用(不理解为什么允许这么做)

    关于这个合成析构函数,《c++ primer 第四版》这么说的:

    ……编译器总会 为我们合成一个析构函数……合成析构函数按对象创建时的逆序撤销每个非static成员,因此,它按成员在类中声明次序的逆序撤销成员,对于类类型的成员,合成析构函数调用该成员的析构函数来撤销对象……即使我们编写了自己的析构函数,合成析构函数依旧运行……

    这里有以下几点理解:

    1.合成析构函数不管你建不建析构函数他都有;

    2.合成析构函数负责销毁对象本身,例如我们对象含有一个int成员时,合成析构函数可以回收这个int成员占用的空间(一个不含有成员变量的类的sizeof=1);这是合成析构函数真正做的事情;

    3.我们的析构函数是对合成析构函数的扩展,所以我们常常在合成析构函数中析构堆中的资源;

    4.按照合成析构函数和析构函数的分工,可以理解必然是先运行手动建立的析构函数,再运行合成析构函数;

    以上是关于析构函数和合成析构函数的理解。

    展开全文
  • C++析构函数

    2021-02-12 09:55:21
    析构函数 1.析构函数定义 2.析构函数作用 执行用户希望在最后一次使用对象之后所执行的任何操作,通常用来...一个类可以多个构造函数,但只能有一个析构函数 用户没有定义析构函数,系统会自动生成一个析构函数 ...

    析构函数

    1.析构函数定义

    在这里插入图片描述

    2.析构函数作用

    执行用户希望在最后一次使用对象之后所执行的任何操作,通常用来清理资源(动态分配的内存,文件描述符)

    3.析构函数调用

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

    4.注意

    一个类可以有多个构造函数,但只能有一个析构函数

    用户没有定义析构函数,系统会自动生成一个析构函数

    展开全文
  • 构造函数与析构函数

    2016-02-16 14:46:56
    (1) 一个类可以包含多个构造函数,各个构造函数之间通过参数列表进行区分。 (2)类的构造函数通过使用冒号:运算符提供了初始化成员的方法。 2.析构函数 析构函数在对象超出作用范围或使用delete运算符释放对象时...
  • 前言,在c++面试过程中,最能考察类的基础知识的莫过于写一个具有类的必要函数的类。...定义一个类如下 class String { public: String(const char *str=NULL); ~String(); String(const String &others);
  • 多态是面向对象的一个基本属性,包括静态多态(编译阶段)和动态多态(运行阶段),静态多态主要是指函数参数不同产生的态性,是在编译阶段可以识别的一种多态机制,而运行时多态则主要用于基类指针指向派生对象...
  • 析构函数(只能有一个)3.malloc、free、new、delete 区别4. 拷贝构造函数和调用场景 知识点: 面试题:finalize , finally, final 之间的区别 finalize : java中垃圾回收回收该对象的时候会调用的方法 (c 中的析构...
  • (二)析构函数析构函数的...②不返回任何值,没有函数类型,也没有函数参数,由于无函数参数,则不能被重载,一个类只能有一个析构函数,但可以多个构造函数。 ③一般情况下,在声明类的同时就定义析构函数。 ...
  • C++之虚析构函数

    2019-03-17 14:37:08
    析构函数可以正常的销毁多态模式下的派生对象,防止造成一个诡异的“局部销毁”对象,从而防止形成内存泄漏。 使用场景 带有多态性质的基类应该声明一个 virtual 析构函数。如果 class 带有任何 virtual 函数,...
  • 1.每个析构函数(不加 virtual) 只负责清除自己的成员。 2.可能有基类指针,指向的确是派生成员的情况。(这是很正常的),  那么当析构一个指向派生成员的基类指针时,程序就不知道怎么办了。   所以要保证...
  • 4)可以多个构造函数(即函数重载形式) 构造函数的种类 默认构造函数 自定义的构造函数 拷贝构造函数 赋值构造函数 默认构造函数 没有参数的构造函数,称为默认构造函数。 1.合成的默认构造函数 构造函数函数名...
  • C++:析构函数

    2019-09-24 23:25:54
    析构函数的特点: 1、析构函数与类名相同,但它...一个类可以多个构造函数,但是只能有一个析构函数 4、撤销对象时,编译系统会自动调用析构函数 //例3.13 含有析构函数和构造函数的Conplex类 #include&l...
  • 每个类只有一个析构函数,但可以多个构造函数(包含一个拷贝构造函数,其他为普通构造函数)和多个赋值函数(包括一个拷贝赋值函数,其他为普通赋值函数)。 一般,对于任意一个类A,如果程序员不显式地声明和定义...
  • 多态是面向对象的一个基本属性,包括静态多态(编译阶段)和动态多态(运行阶段),静态多态主要是指函数参数不同产生的态性,是在编译阶段可以识别的一种多态机制,而运行时多态则主要用于基类指针指向派生对象...
  • 今天看《c++ primer》的时候,突然看到合成析构函数这个名词,对析构函数了解的多点,对合成析构函数则了解的不析构函数特点: 1.整个只有一个,即不能重载; 2.没有形参; 3.没有返回值; 4.不能被继承...
  • 构造函数名称与类名一样,不返回任何类型,也不会返回void,一个类可以多个构造函数 构造函数分为 默认构造 带参构造 拷贝构造 赋值构造 默认构造函数   一般情况下是一个没有参数的空函数,也可以提供一些...
  • 任意一个类只有一个析构函数和一个赋值函数,但可以多个构造函数(包含一个拷贝构造函数,其它的称为普通构造函数) 如果不显式定义这些函数,则编译器为类产生四个缺省函数:缺省的无参数构造函数、缺省的拷贝...
  • 概念 析构函数是一种特殊的成员函数,它执行与构造函数相反的操作,通常用于撤销对象时的...(考试常考:一个类可以多个构造函数但只有一个析构函数。) 析构函数每个类必须会有,如果没有定义析构函数,系统会调...
  • 构造函数与析构函数 一.构造函数 1. 特点: 函数名和类名完全相同 ...构造函数可以有任意类型和任意个数的参数,一个类可以多个构造函数(重载) 2. 默认构造函数 如果程序未声明,则系统会自动产生出一个不带参数
  • 除了本身的定义,包括的创建,构造函数的声明(4个不同的构造函数),函数的定义(showinfo),析构函数(一个就够了),可以看到构造函数的重载,不同参数个数之间,构造函数的命名方式,域空间解析运算符的使用,...
  • 虚函数的访问指针访问引用访问对象访问成员函数中的访问构造函数和析构函数中访问纯虚函数抽象析构函数重载、隐藏、覆盖虚拟继承虚拟继承时派生对象的构造和析构 什么是多态? **态性( polymorphism )**是...
  • 目录定义主要特点C++的构造函数定义格式示例1:不带参数的构造函数示例2:带参数的构造...特别的一个类可以多个构造函数 ,可根据其参数个数的不同或参数类型的不同来区分它们 即构造函数的重载。 主要特点 1.构造...

空空如也

空空如也

1 2 3 4 5 ... 15
收藏数 281
精华内容 112
关键字:

一个类可以定义多个析构函数