下面代码的输出是什么?(D)

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         //析构 对象aclass 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);
}
// 结果为
A
A
B
~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);}
//结果显示
A
A
copy A
B
~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;
};voidmain(void){ A a; B b(a);}
//结果为
A
A
A
B
~B
~A
~A
~A

Aesthetic92:
答案:选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 A
create C
create B
------------------------
~B
~C
~A

我们可以看到,这个地方先是调用parent class的构造函数,然后对成员变量C类型的构造函数,然后再最后执行B类型的构造函数。
析构的过程就是上面的过程反过来。

所以Aesthetic92的解释有一部分不是很准确。我认为。

更加准确的说明应该是,
最开始析构b,~B,这个是没有争议的。
接着是析构b的成员变量_a,所以是~A
接着是b的parent class(基类)的~A
最后才是a的析构~A
不过为了理解这道题,我感觉配上我的例子更好理解一点,原题的成员变量和基类都是相同的类型,比较难以辨认。

构造函数和析构函数的调用过程相关推荐

  1. c++构造函数和析构函数的调用顺序研究

    构造函数与析构函数的调用顺序 构造函数与析构函数的调用顺序 构造函数与析构函数的调用顺序 1)当类中有成员变量是其它类的对象时,首先调用成员变量的构造函数,调用顺序与声明顺序相同:之后调用自身类的构造 ...

  2. 构造函数及析构函数的调用

    构造函数以及析构函数的调用 #include <iostream> using namespace std; class Person { public:Person(){cout < ...

  3. 实验3.1 定义一个CPU类,观察构造函数和析构函数的调用顺序

    题目 定义一个CPU类,包含等级(rank).频率(frequency).电压(voltage)等属性,有两个公有成员函数run.stop.其中,rank为枚举类型CPU_Rank,定义为enum C ...

  4. (c++)5.4构造函数和析构函数中调用虚函数

    在构造函数和析构函数中调用虚函数时,采用静态联编(他们所调用的虚函数是自己类中定义的函数) 如果在自己类中没有实现这个虚函数,则调用的是基类中的虚函数,绝不会是任何在派生类中重定义的虚函数 //构造函 ...

  5. 构造函数和析构函数的调用顺序

    目录 构造函数和析构函数 构造函数 复制构造函数 析构函数 构造函数与析构函数的调用顺序 单继承 多继承 构造函数和析构函数 构造函数 构造函数是特殊的成员函数,与类同名,没有返回类型,而且允许重载. ...

  6. C++核心准则C.82:不要在构造函数或析构函数中调用虚函数

    C.82: Don't call virtual functions in constructors and destructors C.82:不要在构造函数或析构函数中调用虚函数 Reason(原因 ...

  7. C++经验(四)-- 基类构造函数和析构函数中调用virtual虚函数?

    class Base {public:Base();virtual void oneFunction() = 0;... };Base::Base() {...oneFunction(); }clas ...

  8. 继承关系中构造函数、析构函数的调用顺序详解

    构造函数: 在c++中,当声明一个派生类的对象时,派生类中包含所有父类的数据成员以及自己添加的数据成员均已被分配了内存,只是尚未进行初始化配置(但实际上基本数据类型的变量已经被赋予随机默认值). 构造 ...

  9. C++中最好不要在构造函数和析构函数中调用虚函数!!!

    1.最好不要在基类和派生类的构造和析构函数中调用虚函数,不会出现多态性 实例如下: #include "iostream"using namespace std;class Bas ...

最新文章

  1. iOS - OC iOS 开发体系
  2. mac php命令行模式,phpstorm分别在Mac和Windows下启动命令行,并启用ssh
  3. java来构造邻接矩阵
  4. Windows USB驱动开发点滴积累备忘录
  5. pptv图标出现在计算机磁盘,PPTV出现界面乱码如何解决
  6. c语言基础知识scanf,C语言基础之scanf函数的使用
  7. 老男孩Linux高新运维第28期最终篇+老男孩Linux运维+老男孩linux运维全套
  8. 从“洗脸巾”到“湿厕纸”,生活用纸的品类扩张之路
  9. 校招----青颖飞帆二面面经
  10. 决策树CART、ID3、C4.5原理梳理
  11. php使用addons,GitHub - yuninf/tp5-addons: ThinkPHP addons autoload
  12. python简单爬虫 多线程爬取京东淘宝信息教程
  13. php steam 第三方登录,Steam第三方授权登录异常 《绝地求生》国服绑定中招
  14. 聊聊苹果审核——App Store Review Guidelines
  15. bootstrap读书笔记
  16. LuLu UI表单验证
  17. Java 热更新 加载class和jar
  18. docker 基础命令操作 镜像以及容器的基本操作演示
  19. 查看tomcat启动日志
  20. 派森诺群体遗传进化专题之进化树

热门文章

  1. python中使用rsa加密
  2. Java架构师成长之道之浅谈计算机系统架构
  3. MOCTF-火眼金睛
  4. MFC - 获取程序当前路径
  5. SQL Prompt 5.1使用
  6. == Equals ReferenceEquals 的区别
  7. Q+ Web 改版设计小结
  8. 转载-IronPython入门:什么是IronPython?
  9. 理解ASP.NET MVC Framework Action Filters(翻的)
  10. ip rule,ip route,iptables 三者之间的关系