C++中的拷贝构造函数在下面哪些情况下会被调用( BCD )?
A. 对象创建的时候
B. 使用一个类的对象去初始化该类的一个新对象
C. 被调用函数的形参是类的对象
D. 当函数的返回值是类的对象时,函数执行完成返回调用者


什么情况下系统会调用拷贝构造函数?

  1. 用类的一个对象去初始化另一个对象时;
  2. 当函数的形参是类的对象时,即值传递时,引用传递则不会调用;
  3. 当函数的返回值是类的对象或引用时。

拷贝构造函数的调用实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <iostream>
using namespace std;

class A {
int a;
public:
A(int a) : a(a) {}
A(const A& obj) {
a = obj.a;
cout << "A(const A& obj)";
}
int geta() {
return a;
}
};

// 函数的形参是类的对象,值传递
int geta_byVal(A obj) {
return obj.geta();
}

// 函数的形参是类的对象,引用传递
int geta_byRef(A& obj) {
return obj.geta();
}

// 函数的返回值是类的对象
A ret_Aval(A& obj) {
return obj;
}

// 函数的返回值是类的引用
A& ret_Aref(A& obj) {
return obj;
}

int main() {
A obj1(1);

cout << "A obj2(obj1): ";
A obj2(obj1);
cout << endl;

cout << "A obj3 = obj1: ";
A obj3 = obj1;
cout << endl;

cout << "int geta_byVal(A obj): ";
int a = geta_byVal(obj1);
cout << endl;

cout << "int geta_byRef(A& obj): ";
a = geta_byRef(obj1);
cout << endl;

cout << "A ret_Aval(A& obj): ";
A obj4 = ret_Aval(obj1);
cout << endl;

cout << "A& ret_Aref(A& obj): ";
A obj5 = ret_Aref(obj1);
cout << endl;

return 0;
}

/* 运行结果:
A obj2(obj1): A(const A& obj)
A obj3 = obj1: A(const A& obj)
int geta_byVal(A obj): A(const A& obj)
int geta_byRef(A& obj):
A ret_Aval(A& obj): A(const A& obj)
A& ret_Aref(A& obj): A(const A& obj)
*/

从运行结果来看,当我们用类的一个对象去初始化另一个对象时(直接拷贝构造或赋值构造),都会调用拷贝构造函数;当函数的形参是值传递时,会调用拷贝构造函数,而引用传递不会;已知引用传递不会调用拷贝构造函数,我们传入类对象的引用并将它返回,可以看出当函数的返回值是类的对象或引用时,都会在返回时调用拷贝构造函数。

进一步测试发现,当函数返回值为右值引用时(return move(obj);),如果实现了移动拷贝构造,就会调用移动拷贝构造;如果只实现了复制拷贝构造,则会调用复制拷贝构造。当然也可以直接调用移动拷贝构造函数。下面为补充实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 类 A 中实现移动拷贝构造函数:
A(A&& obj) {
a = obj.a;
cout << "A(A&& obj)";
}

// 类外编写函数测试
// 函数的返回值是右值引用
A&& retArefRight() {
A t(1);
return move(t);
}

// 主函数中调用测试函数,输出:A&& retArefRight(): A(A&& obj)
cout << "A&& retArefRight(): ";
A obj6 = retArefRight();
cout << endl;

// 主函数中直接调用移动拷贝构造,输出:A(move(obj6)): A(A&& obj)
cout << "A(move(obj6)): ";
A obj7 = A(move(obj6));
cout << endl;

参考

调用拷贝构造函数的几种情况