构造函数和析构函数的调用过程
来源:互联网 发布:c语言开平方怎么写 编辑:程序博客网 时间:2024/04/29 05:39
class A { public: A() { } ~A() { cout<<"~A"<<endl; } }; class B:public A { public: B(A &a):_a(a) { } ~B() { cout<<"~B"<<endl; } private: A _a; }; int main(void) { A a; //很简单,定义a的时候调用了一次构造函数 B b(a); }A、~B
B、~B ~A
C、~B ~A ~A
D、~B ~A ~A ~A
been:
B(A &a):_a(a)
这个引用也是值得注意的,这里提醒大家一下,去掉引用,第一个析构是是~A
灵灵:
下面以例子说明参数为类对象,是否有初始化列表时构造与析构函数的执行顺序:
#include <iostream>using namespace std; class A{public: A(){ cout<<"A"<<endl; } A(const A& other){ cout<<"copy A"<<endl;} ~A() { cout<<"~A"<<endl; } };class B:public A{ public: B(A a):_a(a) // B(A &a):_a(a) 会有完全不同的结果 { cout<<"B"<<endl; } ~B() { cout<<"~B"<<endl; }private: A _a;}; void main(void){ A a; B b(a); return; } 运行结果:A //A a 创建对象a执行A类的构造 copy A //B b(a) 传参的时候利用A类的复制构造 A //创建对象B调用基类A的构造 copy A //使用初始化列表初始化成员_a利用A类的复制构造 B //调用自己的构造 ~A //析构参数 ~B //析构自身 ~A //析构B类成员 ~A //再析构基类的 ~A //析构 对象a class A{public: A(){ cout<<"A"<<endl; } A(const A& other){ cout<<"copy A"<<endl;} ~A() { cout<<"~A"<<endl; } };class B:public A{ public: B(A a) //若此处换为:B(A &a),则不调用构造函数 { cout<<"B"<<endl; } ~B() { cout<<"~B"<<endl; }private: A _a;}; void main(void){ A a; B b(a); return; } 运行结果:A <span style="font-family: Arial, Helvetica, sans-serif;">//A a 创建对象a执行A类的构造</span> copy A //B b(a) 传参的时候利用A类的复制构造 A //创建对象B调用基类A的构造 A //初始化B类的成员执行A类的构造 B //调用自己的构造 ~A //析构参数 ~B //析构自身 ~A //析构B类成员 ~A //再析构基类的 ~A //析构 对象a
vzhuzhu:
对于构造函数:基类构造函数 > 子类成员变量构造函数 > 子类构造函数
对于析构函数:子类析构函数 > 子类成员变量析构函数 > 基类析构函数
可以看出构造函数的调用过程和析构函数的调用过程正好相反。
水泽渊:
在vs上运行之后发现,输出顺序确实如@Aesthetic92所说,然而@赖聪林说的也没有错,可是@赖聪林举的例子并没有用到拷贝构造函数。
原题-----------------------------------------------------------------------------
class A{ public: A() { cout<<"A"<<endl; } ~A() { cout<<"~A"<<endl; } }; class B:public A { public: B(A &a):_a(a) { cout<<"B"<<endl; } ~B() { cout<<"~B"<<endl; } private: A _a; }; void main(void) { A a; B b(a); }// 结果为AAB~B~A~A~A
加上拷贝构造函数----------------------------------------------------------------------
<pre name="code" class="cpp"> class A {public: A(){ cout<<"A"<<endl; } A(const A& other){ cout<<"copy A"<<endl;} ~A() { cout<<"~A"<<endl; } }; class B:public A { public: B(A &a):_a(a) { cout<<"B"<<endl; } ~B() { cout<<"~B"<<endl; } private: A _a; }; void main(void) { A a; B b(a); } //结果显示AAcopy AB~B~A~A~A
修改后----------------------------------------------------------------------------------
class A { public: A() { cout<<"A"<<endl; } A(const A& other){ cout<<"copy A"<<endl;} ~A() { cout<<"~A"<<endl; } }; class B:public A { public: B(A &a) { cout<<"B"<<endl; } ~B() { cout<<"~B"<<endl; } private: A _a; }; void main(void) { A a; B b(a); } //结果为AAAB~B~A~A~A
答案:选D
答案解析:答案看起来可能比较怪,其实给默认构造函数补上输出,然后再在基类里写个复制构造函数,这样结果就很明朗了;
首先 A a;这个调用A的默认构造函数,
B b(a); 因为A &a,形参为引用,不需要调用基类复制构造函数(其实基类也没写);_a(a)首先创建对象_a,调用基类A的默认构造函数,然后调用基类复制构造函数(测试的时候可以写出来),把a对象赋给_a,结束之后调用B的析构函数,输出~B;然后调用基类A的析构函数撤销复制构造函数,输出~A;调用基类A的析构函数撤销_a,输出~A;最后调用基类A的析构函数撤销一开始创建的A a,输出~A
kuring:
要想搞明白该问题,需要理解基类构造析构函数、子类构造析构函数和子类成员变量构造析构函数的调用顺序。
对于构造函数:基类构造函数 > 子类成员变量构造函数 > 子类构造函数
对于析构函数:子类析构函数 > 子类成员变量析构函数 > 基类析构函数
可以看出构造函数的调用过程和析构函数的调用过程正好相反。
main函数中首先构造变量a,然后是b。在构造b时首先调用b的基类A的构造函数,然后调用b中成员变量_a的构造函数,最后调用b的构造函数。
main函数调用结束返回时,变量的释放顺序跟变量的构造顺序正好相反。首先释放变量b,然后是变量a。
在释放变量b时,首先调用b的析构函数,然后析构变量b的成员_a,析构_a时调用_a的析构函数。再调用b的基类的析构函数。
然后是释放变量a,调用a的析构函数。
本例子中应该将A的析构函数更改为virtual的,防止使用多态机制时出现子类对象无法释放的情况,本例子中没有用到多态机制,不存在该问题。
赖聪林:
# include <iostream>using namespace std;class A { public: A() { cout<<"create A"<<endl; } A(const A& other){ cout<<"copy A"<<endl;} //复制构造函数 ~A() { cout<<"~A"<<endl; } }; class C{public: C() { cout<<"create C"<<endl; } C(const A& other){ cout<<"copy C"<<endl;} //复制构造函数 ~C() { cout<<"~C"<<endl; } };class B:public A { public: B() { cout<<"create B"<<endl; } ~B() { cout<<"~B"<<endl; } private: C _a; }; int main(void) { B b; cout<<"------------------------"<<endl;} //上面的输出结果为create Acreate Ccreate B------------------------~B~C~A
我们可以看到,这个地方先是调用parent class的构造函数,然后对成员变量C类型的构造函数,然后再最后执行B类型的构造函数。
析构的过程就是上面的过程反过来。
所以Aesthetic92的解释有一部分不是很准确。我认为。
更加准确的说明应该是,
最开始析构b,~B,这个是没有争议的。
接着是析构b的成员变量_a,所以是~A
接着是b的parent class(基类)的~A
最后才是a的析构~A
不过为了理解这道题,我感觉配上我的例子更好理解一点,原题的成员变量和基类都是相同的类型,比较难以辨认。
- 构造函数和析构函数的调用过程
- 全局变量,继承,虚函数,构造函数和析构函数的调用过程
- 构造函数、拷贝构造函数和析构函数的的调用时刻及调用顺序
- 构造函数、拷贝构造函数和析构函数的的调用时刻及调用顺序
- 构造函数、拷贝构造函数和析构函数的的调用时刻及调用顺序
- 构造函数、拷贝构造函数和析构函数的的调用时刻及调用顺序
- 构造函数和析构函数的调用
- 构造函数和析构函数的调用次序
- 关于构造函数和析构函数的调用顺序
- 构造函数和析构函数的相互调用
- C++构造函数和析构函数的调用顺序
- C++构造函数和析构函数的调用顺序
- 7.23构造函数和析构函数的调用次序
- 构造函数和析构函数的调用问题
- 析构函数和构造函数的调用顺序
- 调用构造函数和析构函数的顺序
- 构造函数和析构函数的调用顺序
- 浅谈构造函数和析构函数的调用顺序
- 归并排序
- 欢迎使用CSDN-markdown编辑器
- java date20150819
- JAVA基本数据类型
- 日志处理(文件的读出和写入)
- 构造函数和析构函数的调用过程
- Protocol - 5
- LRU Cache
- 算术运算符
- 黑马程序员=====Java基础---继承、抽象、接口
- 初次安装Android Studio之环境设置
- [Leetcode]Kth Smallest Element in a BST
- JavaScript+CSS实现图片动态轮播dynamic_slider
- python函数之strip()