首页 > 试题广场 >

分析一下这段程序的输出

[单选题]
分析一下这段程序的输出
#include<iostream>
 using namespace std;
 class B
 {
 public:
     B()
     {
         cout << "default constructor" << " ";
     }
     ~B()
     {
         cout << "destructed" << " ";
     }
     B(int i): data(i)
     {
         cout << "constructed by parameter" << data << " ";
     } 
     private: int data;
 }; 
 B Play( B b)
 {
     return b;
 } 
 int main(int argc, char *argv[])
 {
     B temp = Play(5);
     return 0;
 }

  • constructed by parameter5  destructed  destructed
  • constructed by parameter5  destructed
  • default constructor"  constructed by parameter5 destructed
  • default constructor"  constructed by parameter5 destructed  destructed
推荐
  1. 调用Play函数需要将5隐式类型转换为Play函数中的形参b,会调用B的B(int i): data(i),打印“constructed by parameter5”。
  2. Play函数返回时需要调用B的复制构造函数给对象temp初始化。
  3. Play函数返回后需要调用b的析构函数,将Play函数的形参释放,打印“destructed”。
  4. main函数返回后需要释放temp,打印“destructed”。

选A
编辑于 2015-01-26 20:05:44 回复(13)
因为temp是在main函数返回后释放,所以temp的”destructed“没有打印出来
编辑于 2015-09-25 10:51:38 回复(0)
答案: B
解释:
首先要说明的是,若用户没有定义,C++隐式声明一个复制构造函数和一个赋值运算符(完成按数据成员复制的动作)。二者很像,但是在下边这点上有很大的不同:复制构造函数是只在对象实例化时才会被调用,也就是说,在复制构造函数调用期间,这个对象处于一个未决状态(直到复制构造函数被成功调用),另外复制构造函数不返回任何值,void都没有。而赋值运算符则在一个现存的对象被赋予新的值时被调用,并且它有返回值。

如果添加上复制构造函数:
B(const B & r)

{
cout << "copy ctor " << "  ";
}
那么输出:constructed by parameter5 copy ctor destructed

发表于 2015-01-07 17:42:57 回复(6)
赋值运算符的结合顺序是从右到左的,所以是先算的play(5)
发表于 2017-04-28 21:21:22 回复(0)
B temp = Play(5);
这句话的过程:

首先Play(5) 调用 类B中的 B(inti)构造函数,
/*
这里是其实是隐式转换
所以看到int 型的 5 ,会去调用B的构造函数
如果是explicit  B(inti): data(i) 就会报错
*/

接着将这个对象传给 B的拷贝构造函数,去初始化 temp

拷贝构造函数是默认的,如果不声明,编译器会自动给你一个默认的拷贝构造函数



编辑于 2015-10-03 21:55:05 回复(0)
选A
这个题目纠结了很久,在想到底会调用几次拷贝构造函数。于是自己敲了一遍代码,把拷贝构造加进去了。


个人觉得,
  1. 在Play(5)传递实参之前会隐式调用一次带参构造将5转换为B类型
  2. 传参是值传递,会调用拷贝构造函数
  3. Play函数返回一个匿名B类型对象,调用拷贝构造函数
  4. 用返回的匿名对象初始化temp,再次调用拷贝构造函数
  5. temp构造完毕调用析构函数释放匿名对象
  6. 调用析构函数释放给Play函数传递的实参
  7. 调用析构函数释放隐式调用生成的对象
  8. 最后调用析构函数释放temp
不知道这顺序到底对不对,但从我用gdb调试来看是这样的,gdb调试太繁琐就不一一列出了
当然直接用g++编译只会出现一次拷贝构造,如下图所示

这是因为RVO(return value optimization)机制的存在,使得拷贝构造被G++进行值返回的优化了
可以对g++增加选项-fno-elide-constructors将RVO优化关闭,重新编译即可得到以下结果

发表于 2018-04-03 15:50:24 回复(6)
选A

1.调用Play函数时,会将5隐式的转换为形参b的类型,会调用B的B(int i):data(i),打印”constructed by parameter5“
2.Play函数返回时,temp调用B的默认浅拷贝构造函数,完成赋值,由于拷贝构造函数没有输出,所以没有打印东西
3.Play函数返回后,调用b的析构函数,输出”destructed“
4.main函数返回,调用temp的析构函数,输出”destructed“
编辑于 2017-02-19 19:19:15 回复(5)
注意调用方式的区别。
如果是B temp = Play(5);则选A
如果是B temp(5),则选B
发表于 2017-01-14 08:51:18 回复(1)

1.调用Play函数时,会将5隐式的转换为形参b的类型,会调用B的B(int i):data(i),打印”constructed by parameter5“
2.Play函数返回时,temp调用B的默认浅拷贝构造函数,完成赋值,由于拷贝构造函数没有输出,所以没有打印东西(注意此处用的是拷贝构造函数)
3.Play函数返回后,调用b的析构函数,输出”destructed“
4.main函数返回,调用temp的析构函数,输出”destructed“
发表于 2018-06-02 09:03:39 回复(0)
play()是类外定义的参数和返回值均为B类对象类型的函数 。 只有一个参数的构造函数定义了一个隐式转换,将改构造函数对应数据类型的数据转换为该类对象。 因此函数调用play(5)时,5先隐式转换为B类对象,调用B(int i)构造函数,输出“constructed by parameter 5” 。 play()返回对象时调用默认复制构造函数复制一个新对象,赋值给temp,没有输出 。 函数调用完毕释放b,输出“destructed”。 最后main结束释放temp,输出“destructed”。
编辑于 2018-04-15 21:31:51 回复(0)
为什么B temp不调用默认构造函数,求解答!
发表于 2017-06-06 12:05:12 回复(5)
dp头像 dp
没想到play函数 形参中的 b 竟然也是 一个初始化的B对象,而且还调用了 赋值构造函数,
最后一个destructed 属于 tmp 要main 返回才能输出
发表于 2015-11-22 20:04:46 回复(0)
Play(5)相当于创建了一个临时对象,调用B(int i)的构造函数,给play函数的形参赋值,调用默认的拷贝构造函数,所以程序快要结束时,有两次析构
发表于 2023-10-06 15:21:03 回复(0)
返回时 移动构造 所以只有两个对象两次折构 其中移动语义是编译器优化和默认生成
发表于 2022-03-28 19:10:36 回复(0)
这是初始化
发表于 2021-11-26 22:59:06 回复(0)
拷贝构造函数没有输出语句,所以没有输出信息
发表于 2021-05-24 17:15:26 回复(0)

先执行右边参数构造的有输出;然后调用拷贝构造函数,没有输出;最后调用析构2次,一次是参数对象的,另外一次是拷贝构造对象~

编辑于 2021-09-02 18:58:17 回复(0)
我能说我没看懂英文吗。。
发表于 2019-05-02 10:58:51 回复(0)
调用Play函数时进行隐式转化  调用参数构造函数
play函数返回的是新匿名对象 ,但是此时b面临析构,所以此时进行形成匿名对象进行右值引用构造,因为题中没定义所以没显示
b析构
在main函数中有新对象temp,由匿名对象进行赋值,此时不调用任何的构造函数,因为此时的temp是对匿名对象生命周期的延长
出了main右括号,temp析构。
大家了解一下 移动语义,play()函数返回class B的右值引用,比较新的编译器会避免再构造一个对象,直接让temp接管了这个对象,此时只有一个对象被创建
你们多试试把  实践出真知.....一楼的说的貌似不对。。

编辑于 2019-04-14 15:17:02 回复(0)
编译器做了优化,实际编译过程没有临时对象的构造和析构过程啊,所以选B
发表于 2019-03-26 23:29:46 回复(0)
它这里没有实现拷贝构造,所以使用的是默认的拷贝构造函数
发表于 2019-03-12 20:45:48 回复(0)