C++

调用拷贝构造函数的场景

Posted by DEVIN on Sun, Jun 18, 2023

1.默认构造函数

默认构造函数是一个系统生成的,参数列表和函数体都为空的函数。 如果类中声明了默认构造函数(无论是否有参数),编译器便不再会为之生成隐含的构造函数。

2.析构函数

  • 析构函数的函数列表为空,因此不能实现重载。
  • 可以显式调用析构函数。例如可以通过对象名等进行调用,obj.~A();

参考文献:显式调用析构函数

3.拷贝构造函数

拷贝构造函数的参数**必须是引用类型。**参数是指针不会编译报错,但是3.1中的场景不能触发调用拷贝构造函数。

3.1 调用拷贝构造函数的3种场景

  • 用一个类的对象去初始化另一个类的对象时
1Point a(1, 2);
2Point b(a); // 调用复制构造函数
3Point c = a; // 调用复制构造函数
  • 函数的形参是类对象,当调用函数,进行形参和实参结合时
1void fun(Point obj) {}
2
3int main() {
4	Point a(1, 2);
5    fun(a); // 调用复制构造函数
6}
  • 如果函数的返回值是类对象,当函数执行完成返回调用者时

实际上,由于编译器的优化,可能不会调用。例如:gcc需要指定**-fno-elide-constructors**编译选项才会调用。

1Point fun() {
2	Point a(1, 2);
3    return a; // 调用复制构造函数
4}
5
6b = fun();

4.赋值运算符

4.1 注意点

  • **拷贝构造函数必须以引用的方式传递参数,**基本上都是传常量引用的方式传递函数参数。
  • 赋值运算符函数的返回值类型要声明为该类型的引用,并在函数结束前返回实例自身的的引用(this*。**只有返回一个引用,才能进行连续赋值。否则,如果函数的返回值是void,则应用该赋值运算符将不能进行连续赋值。假设有3个Person对象:p1、p2、p3,在程序中语句p1=p2=p3将不能通过编译。
  • 关于深拷贝和浅拷贝:当类有指针成员或有动态分配空间,都应实现自定义的拷贝构造函数。提供了拷贝构造函数,最后也实现赋值运算符。

4.2 和拷贝构造函数的区别

  • 区别:拷贝构造函数使用已有的对象创建一个新的对象,赋值运算符是将一个对象的值复制给另一个已存在的对象。区分是调用拷贝构造函数还是赋值运算符,主要是否有新的对象产生
 1#include <iostream>
 2using namespace std;
 3
 4class A {
 5public:
 6    A(string str) : name(str) { cout << "construct " << name << endl; } // 构造函数
 7    A(const A &other) { // 拷贝构造函数
 8        name = "copy " + other.name;
 9        cout << name << endl;
10    }
11    A& operator = (const A &other) { // 赋值运算符重载
12        name = "equal " + other.name;
13        cout << name << endl;
14        return *this;
15    }
16
17    string name;
18};
19
20void fun1(A obj) {}
21
22A fun2() {
23    A obj1("obj1");
24    return obj1;
25}
26
27int main()
28{
29    A a("a");
30    // 下面3行都是调用拷贝构造函数
31    A b(a);
32    A c = a;
33    fun1(a);
34    cout << "-----------" << endl;
35    fun2();
36    cout << "-----------" << endl;
37    // 调用赋值运算符
38    b = a;
39}
40
41/* 输出:
42construct acopy a
43copy a
44copy a
45-----------
46construct obj1
47copy obj1 (指定-fno-elide-constructors编译选项才有这一项输出)
48-----------
49equal a
50*/

参考文献

1. C++ 拷贝构造函数和赋值运算符 2. C++ 拷贝构造函数和赋值运算符函数及其必要性和意义 3. 为什么拷贝构造函数自己的参数必须是引用类型 - 知乎