精华内容
下载资源
问答
  • 2020-08-21 09:22:58

    牛客上看到了这个问题:

    C c;
    void main()
    {
        A*pa=new A();
        B b;
        static D d;
        delete pa;
    }
    

    问析构的顺序:

    全局变量,静态局部变量,局部变量空间的堆分配和栈分配

    其中全局变量和静态局部变量时从 静态存储区中划分的空间,
    二者的区别在于作用域的不同,全局变量作用域大于静态局部变量(只用于声明它的函数中),
    而之所以是先释放 D 在释放 C的原因是, 程序中首先调用的是 C的构造函数,然后调用的是 D 的构造函数,析构函数的调用与构造函数的调用顺序刚好相反。

    局部变量A 是通过 new 从系统的堆空间中分配的,程序运行结束之后,系统是不会自动回收分配给它的空间的,需要程序员手动调用 delete 来释放。
    局部变量 B 对象的空间来自于系统的栈空间,在该方法执行结束就会由系统自动通过调用析构方法将其空间释放。
    之所以是 先 A 后 B 是因为,B 是在函数执行到 结尾 “}” 的时候才调用析构函数, 而语句 delete a ; 位于函数结尾 “}” 之前。

    更多相关内容
  • 今天我们来探讨一下类继承中的构造函数和析构函数调用顺序问题。 #include <bits/stdc++.h> using namespace std; class Father { public: Father() { cout << "Father constructor worked\n" &...

    微信搜索:编程笔记本。获取更多干货!
    微信搜索:编程笔记本。获取更多干货!

    点击上方蓝字关注我,我们一起学编程
    欢迎小伙伴们分享、转载、私信、赞赏

    今天我们来探讨一下类继承中的构造函数和析构函数的调用顺序问题。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    class Father {
    public:
    	Father() {
    		cout << "Father constructor worked\n" << endl;
    	}
    	~Father() {
    		cout << "Father destructor worked\n" << endl;
    	}
    };
    
    class Son : public Father {
    public:
    	Son() {
    		cout << "Son constructor worked\n" << endl;
    	}
    	~Son() {
    		cout << "Son destructor worked\n" << endl;
    	}
    };
    
    
    int main()
    {
    	Son son;
    	
        return 0;
    }
    

    微信搜索:编程笔记本。获取更多干货!
    微信搜索:编程笔记本。获取更多干货!

    上面的代码中,Son 公有继承 Father ,当我们定义一个 Son 的对象时,基类和派生类的构造函数与析构函数调用顺粗如下:

    Father constructor worked
    
    Son constructor worked
    
    Son destructor worked
    
    Father destructor worked
    

    可以看到,构造函数是从基类向派生类逐层调用的,析构函数是从派生类向基类逐层调用的。

    问了更好地说明问题,我们增加一个类:

    #include <bits/stdc++.h>
    
    using namespace std;
    
    class GrandFather {
    public:
    	GrandFather() {
    		cout << "GrandFather constructor worked\n" << endl;
    	}
    	~GrandFather() {
    		cout << "GrandFather destructor worked\n" << endl;
    	}
    };
    
    class Father : public GrandFather {
    public:
    	Father() {
    		cout << "Father constructor worked\n" << endl;
    	}
    	~Father() {
    		cout << "Father destructor worked\n" << endl;
    	}
    };
    
    class Son : public Father {
    public:
    	Son() {
    		cout << "Son constructor worked\n" << endl;
    	}
    	~Son() {
    		cout << "Son destructor worked\n" << endl;
    	}
    };
    
    
    int main()
    {
    	Son son;
    	
        return 0;
    }
    
    /*
    运行结果:
    
    GrandFather constructor worked
    
    Father constructor worked
    
    Son constructor worked
    
    Son destructor worked
    
    Father destructor worked
    
    GrandFather destructor worked
    */
    

    微信搜索:编程笔记本。获取更多干货!
    微信搜索:编程笔记本。获取更多干货!

    构造函数调用顺序:从长辈到小辈;析构函数调用顺序:从小辈到长辈。

    同样地,生成对象数组与生成单个对象的情况相同,不再赘述,附上测试代码。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    class GrandFather {
    public:
    	GrandFather() {
    		cout << "GrandFather constructor worked\n" << endl;
    	}
    	~GrandFather() {
    		cout << "GrandFather destructor worked\n" << endl;
    	}
    };
    
    class Father : public GrandFather {
    public:
    	Father() {
    		cout << "Father constructor worked\n" << endl;
    	}
    	~Father() {
    		cout << "Father destructor worked\n" << endl;
    	}
    };
    
    class Son : public Father {
    public:
    	Son() {
    		cout << "Son constructor worked\n" << endl;
    	}
    	~Son() {
    		cout << "Son destructor worked\n" << endl;
    	}
    };
    
    
    int main()
    {
    	Son *pSon = new Son[2];
    	delete[] pSon;
    	
        return 0;
    }
    
    /*
    运行结果:
    
    GrandFather constructor worked
    
    Father constructor worked
    
    Son constructor worked
    
    GrandFather constructor worked
    
    Father constructor worked
    
    Son constructor worked
    
    Son destructor worked
    
    Father destructor worked
    
    GrandFather destructor worked
    
    Son destructor worked
    
    Father destructor worked
    
    GrandFather destructor worked
    */
    

    在上面的例子中,若 delete pSon 的话,会报 munmap_chunk(): invalid pointer, Aborted (core dumped) 错误。

    总结

    对于具有继承关系的类,其构造函数的调用顺序是:先基类、再派生类;其析构函数的调用顺序是:先派生、后基类。

    微信搜索:编程笔记本。获取更多干货!
    微信搜索:编程笔记本。获取更多干货!

    展开全文
  • 在一般情况下,调用析构函数的次序正好与调用构造函数的次序相反:最先被调用的构造函数,其对应的(同一对象中的)析构函数最后被调用,而最后被调用的构造函数,其对应的析构函数最先被调用。 简单来说,其构造函数...

    在使用构造函数和析构函数时,需要特别注意对它们的调用时间和调用顺序。在一般情况下,调用析构函数的次序正好与调用构造函数的次序相反:最先被调用的构造函数,其对应的(同一对象中的)析构函数最后被调用,而最后被调用的构造函数,其对应的析构函数最先被调用。
    简单来说,其构造函数的顺序就一句话:
    基类构造函数 -> 成员的构造函数 -> 构造函数体内语句

    eg.

    #include <iostream>
    
    using namespace std;
    
    class A {
     public:
      A() { cout << "A()" << endl; }
      ~A() { cout << "~A()" << endl; }
    };
    
    class B {
     public:
      B(int b) { cout << "B(" << b << ")" << endl; }
      ~B() { cout << "~B()" << endl; }
    };
    
    class C {
     public:
      C(int c) { cout << "C(" << c << ")" << endl; }
      ~C() { cout << "~C()" << endl; }
    };
    
    class D {
     public:
      D() { cout << "D()" << endl; }
      ~D() { cout << "~D()" << endl; }
    };
    
    class E: public B, public A {
     public:
      D d;
      C c;
      E(): c(3), B(5) { cout << "E()" << endl; }
      ~E() { cout << "~E()" << endl; }
    };
    
    int main()
    {
     E e;
    
     return 0;
    }
    

    首先应该执行的是基类的构造函数。不过 C++ 语言是支持多继承的,那么当某个类继承多个类时,其构造顺序又是怎样的呢?答案是:简单的依照继承的顺序构造。
    接下来,就会执行其成员变量的构造函数,这个顺序也很简单,就是依照类代码中成员变量的顺序依次执行的。

    最后才会执行构造函数中的具体代码。
    注意,在上述过程中,执行的顺序与构造函数参数的顺序无关。
    通过 new 创建一个对象会调用其构造函数,通过 delete 删除一个对象会调用其析构函数。
    如果没有显示的使用 delete 删除一个对象的话,析构函数执行的顺序与构造函数的顺序相反。
    所以,上述代码的输出就是:

    B(5)
    A()
    D()
    C(3)
    E()
    ~E()
    ~C()
    ~D()
    ~A()
    ~B()
    

    下面归纳一下什么时候调用构造函数和析构函数:

    1. 在全局范围中定义的对象(即在所有函数之外定义的对象),它的构造函数在文件中的所有函数(包括main函数)执行之前调用。但如果一个程序中有多个文件,而不同的文件中都定义了全局对象,则这些对象的构造函数的执行顺序是不确定的。当main函数执行完毕或调用exit函数时(此时程序终止),调用析构函数。
    2. 如果定义的是局部自动对象(例如在函数中定义对象),则在建立对象时调用其构造函数。如果函数被多次调用,则在每次建立对象时都要调用构造函数。在函数调用结束、对象释放时先调用析构函数。
    3. 如果在函数中定义静态(static )局部对象,则只在程序第一次调用此函数建立对象时调用构造函数一次,在调用结束时对象并不释放,因此也不调用析构函数,只在main函数结束或调用exit函数结束程序时,才调用析构函数。
    展开全文
  • 就会调用该指针指向的派生类析构函数,而派生类的析构函数又自动调用基类的析构函数,这样整个派生类的对象完全被释放。 (2)析构函数不定义为虚函数时:编译器实施静态绑定,在删除基类指针时,只会调用基类的析构...

    1、析构函数是否定义为虚函数的区别

    (1)析构函数定义为虚函数时:基类指针可以指向派生类的对象(多态性),如果删除该指针delete []p;就会调用该指针指向的派生类析构函数,而派生类的析构函数又自动调用基类的析构函数,这样整个派生类的对象完全被释放。

    (2)析构函数不定义为虚函数时:编译器实施静态绑定,在删除基类指针时,只会调用基类的析构函数而不调用派生类析构函数,这样就会造成派生类对象析构不完全。

    2、派生类指针操作派生类对象,基类析构函数不是虚函数

    class CBase 
    {
    public:
    	CBase() { cout << "CBase!" << endl; };
    	~CBase() { cout << "~CBase!" << endl; };
    
    	void DoSomething() { cout << "Do something in CBase!" << endl; };
    };
    
    class CSubBase : public CBase 
    {
    public:
    	CSubBase() { cout << "CSubBase!" << endl; };
    	~CSubBase() { cout << "~CSubBase!" << endl; };
    
    	void DoSomething() { cout << "Do something in CSubBase!" << endl; };
    };
    
    
    int main(){
    	CSubBase* p = new CSubBase;
    	p->DoSomething();
    	delete p;
    
    	system("pause");
    	return 0;
    }
    
    CBase!
    CSubBase!
    Do something in CSubBase!
    ~CSubBase!
    ~CBase!
    

    3、基类指针操作派生类对象,基类析构函数不是虚函数

    class CBase 
    {
    public:
    	CBase() { cout << "CBase!" << endl; };
    	~CBase() { cout << "~CBase!" << endl; };
    
    	void DoSomething() { cout << "Do something in CBase!" << endl; };
    };
    
    class CSubBase : public CBase 
    {
    public:
    	CSubBase() { cout << "CSubBase!" << endl; };
    	~CSubBase() { cout << "~CSubBase!" << endl; };
    
    	void DoSomething() { cout << "Do something in CSubBase!" << endl; };
    };
    
    
    int main(){
    	CBase* p = new CSubBase;
    	p->DoSomething();
    	delete p;
    
    	system("pause");
    	return 0;
    }
    
    CBase!
    CSubBase!
    Do something in CBase!
    ~CBase!
    

    4、基类指针操作派生类对象,基类析构函数是虚函数

    class CBase 
    {
    public:
    	CBase() { cout << "CBase!" << endl; };
    	virtual ~CBase() { cout << "~CBase!" << endl; };
    
    	void DoSomething() { cout << "Do something in CBase!" << endl; };
    };
    
    class CSubBase : public CBase 
    {
    public:
    	CSubBase() { cout << "CSubBase!" << endl; };
    	~CSubBase() { cout << "~CSubBase!" << endl; };
    
    	void DoSomething() { cout << "Do something in CSubBase!" << endl; };
    };
    
    
    int main(){
    	CBase* p = new CSubBase;
    	p->DoSomething();
    	delete p;
    
    	system("pause");
    	return 0;
    }
    
    CBase!
    CSubBase!
    Do something in CBase!
    ~CSubBase!
    ~CBase!
    

    5、基类指针操作派生类对象,基类析构函数是虚函数,DoSomething是虚函数

    class CBase 
    {
    public:
    	CBase() { cout << "CBase!" << endl; };
    	virtual ~CBase() { cout << "~CBase!" << endl; };
    
    	virtual void DoSomething() { cout << "Do something in CBase!" << endl; };
    };
    
    class CSubBase : public CBase 
    {
    public:
    	CSubBase() { cout << "CSubBase!" << endl; };
    	~CSubBase() { cout << "~CSubBase!" << endl; };
    
    	void DoSomething() { cout << "Do something in CSubBase!" << endl; };
    };
    
    
    int main(){
    	CBase* p = new CSubBase;
    	p->DoSomething();
    	delete p;
    
    	system("pause");
    	return 0;
    }
    
    CBase!
    CSubBase!
    Do something in CSubBase!
    ~CSubBase!
    ~CBase!
    

    6、基类析构函数定义为虚函数的情况

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

    展开全文
  • C++继承中构造函数、析构函数调用顺序及虚析构函数 首先说说构造函数,大家都知道构造函数里就可以调用成员变量,而继承中子类是把基类的成员变成自己的成员,那么也就是说子类在构造函数里就可以调用...
  • 设已经有A,B,C,D4个类的定义,程序中A,B,C,D析构函数调用顺序为? ( ) C c; void main() { A*pa=new A(); B b; static D d; delete pa; } A.A B C D B.A B D C C.A C D B D.A C B D 分析:首先手动释放pa, 所以会...
  • 析构函数参考:http://blog.csdn.net/zengchen__acmer/article/details/22592195?utm_source=tuicool构造函数参考:...C++构造函数调用顺序: 1、创建派生类的对象,基类的构造函数函数优先被调用(也优先于...
  • 4.调用析构函数顺序正好与调用构造函数的顺序相反,先执行派生类的析构函数,再执行内嵌对象成员,最后执行基类的析构函数。 如下代码: #include &lt;iostream&gt; using namespace std; class B...
  • 【C++】析构函数调用顺序

    千次阅读 2015-04-23 22:06:29
    C++学习笔记 函数调用顺序:生成类对象先调用析构函数,对象周期结束,调用析构函数 这个都知道,下面主要说父类与子类之间析构函数调用:class base { public: base() { cout ; } ~base() { cout << "this
  • 在一般情况下,调用析构函数的次序正好与调用构造函数的次序相反:最先被调用的构造函数,其对应的(同一对象中的)析构函数最后被调用,而最后被调用的构造函数,其对应的析构函数最先被调用。 简单来说,其构造函数...
  • 静态变量在所在函数第一次被调用调用构造函数、在程序结束时调用析构函数,只调用一次。 局部变量在所在的代码段被执行时调用构造函数,在离开其所在作用域(大括号括起来的区域)时调用析构函数。可以调用任意多...
  • 析构函数调用顺序

    2020-03-24 10:33:33
    对于不同作用域和存储类别的对象,构造函数he析构函数调用顺序 全局对象 构造函数在文件中所有函数执行前调用 当main函数执行完毕或者是调用exit函数时(此时程序会终止),调用析构函数。 函数中定义的自动...
  • #include using namespace std;class Base { public: Base::Base() { cout 基类构造函数" ; } Base::~Base() { cout 基类析构函数" ; } }; class Son
  • 调用构造函数 和 析构函数的顺序 在使用构造函数和析构函数的时候,需要特别注意对它们的调用时间和调用顺序,如下是一个例子:
  • 声明一个CPU类,包含等级rank,频率frequency,电压voltage等属性,有两个共有函数 // stop 和ran。 // 其中,rank为枚举类型CPU_Rank,声明为enum CPU_Rank{p1=1,p2,p3,p4,p5,p6,p7},frequency为单位 // MHz整数...
  • C++析构函数
  • 派生类的构造函数与析构函数调用顺序 前面已经提到,构造函数和析构函数的调用顺序是先构造的后析构,后构造的先析构。 那么基类和派生类中的构造函数和析构函数的调用顺序是否也是如此呢? 构造函数的调用...
  • 构造函数与析构函数调用顺序构造函数定义特点析构函数定义特点构造函数与析构函数的执行顺序例题 构造函数 定义 构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,保证每个数据...
  • 一、构造函数,会先调用基类的构造函数(第一基类,...二、析构函数,会先析构自己的,然后再逐级向爷爷辈析构。 三、关于内嵌对象:例class Camera{}; (1)在构造函数时:与容器类的构造和析构贴着,方向一致。 ...
  • 生成封闭类对象构造析构函数调用顺序 当封闭类对象生成时1 S1:执行所有成员对象的构造函数 S2:执行封闭类的构造函数 成员对象的构造函数调用顺序 和成员对象在类中的说明顺序一致 与在成员初始化列表中出现的书序...
  • 在C++类中,类A继承类B时,如果创建一个A的对象时,会首先调用基类的构造函数,再调用派生类的构造函数,而析构函数的执行相反,但是当基类和派生类分别有一个成员对象时,构造函数与析构函数的执行顺序又是怎样的呢...
  • 文章目录一、派生类构造函数与基类构造函数二、创建与销毁派生类对象时,构造函数和析构函数调用三、派生类和基类之间的特殊关系四、公有继承(一)、何为公有继承(二)、多态公有继承(三)、虚函数的工作原理...
  • 组合类构造函数、析构函数、拷贝构造函数的调用顺序 这些天在看C++的过程中一直搞不太懂构造函数和析构函数的调用顺序,特别是析构函数,不带参数不好进行测试,这里把这几天遇到的问题写了个代码跑了一下,和大家...
  • C++中有一个很重要的法则:使用构造函数创建对象的顺序与使用析构函数释放对象的顺序相反。对于一些C++的初学者来说,这是一条有点费解的法则,那么该怎么理解和清晰的表现出来呢?下面我们通过程序来体现一下: #...
  • 继承关系中,构造函数、析构函数调用顺序: 在构造派生类时,调用顺序为:父类构造-子类构造-子类析构-父类析构 class Base1 { public: Base1() { cout << "Base1()" << endl; } ~Base1() { cout &...
  • 先建立的对象先用拷贝构造函数,后建立的后用,调用析构函数优先,当删除对象时会自动调用析构函数,先删除后建立的,再删除先调用的。 #include <iostream> #include <string> using namespace std; ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 50,164
精华内容 20,065
关键字:

析构函数的调用顺序

友情链接: jin_xiao_cun.rar