为什么我们使用 const 和 reference 作为参数来复制构造函数?

Rob*_*ert 0 c++ constructor class

考虑以下示例:

#include<iostream> 
using namespace std;

class Point
{
private:
    int x, y;
public:
    Point(int x1, int y1) { x = x1; y = y1; }

    // Copy constructor 
    Point(const Point& p2) { x = p2.x; y = p2.y; }

    int getX() { return x; }
    int getY() { return y; }
};

int main()
{
    Point p1(10, 15); 
    Point p2 = p1; 


    cout << "p1.x = " << p1.getX() << ", p1.y = " << p1.getY();
    cout << "\np2.x = " << p2.getX() << ", p2.y = " << p2.getY();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我们注意到这Point(const Point& p2);是一个复制构造函数。为什么要使用const关键字,为什么要使用引用?我们为什么不使用Point(Point p2);

dfr*_*fri 5

为什么我们使用 const 关键字 [...] ?

不需要const类复制构造函数使用-qualified(甚至 cv-qualified)参数;引用cppreference/复制构造函数

类的复制构造函数T是一个非模板构造函数,它的第一个参数是T&?const T&?volatile T&?、 或const volatile T&?,并且要么没有其他参数,要么其余参数都有默认值。

但是复制构造函数需要改变它用于复制的对象是非常不寻常的

#include <iostream>

struct A {
    int x;
    A(int x_) : x(x_) {}
    A(A& other) : x(other.x) { ++other.x; }
};

int main() {
    A a1{42};  // a1.x is 42.
    A a2(a1);  // a2.x is 42, AND a1.x is 43
    std::cout << a1.x << " " << a2.x;  // 43 42
}
Run Code Online (Sandbox Code Playgroud)

而且,非const引用不能绑定到右值来延长它们的生命周期,这意味着这样的复制构造函数不能用于从临时对象复制初始化。即,以下(常见情况)是格式良好的:

struct A {
    int x;
    A(int x_) : x(x_) {}
    A(const A& other) : x(other.x) { }
    static A create() { return {12}; };
};

int main() {
    A a1(A::create());  // OK.
}
Run Code Online (Sandbox Code Playgroud)

而以下格式不正确(在 C++17 中保证复制省略之前):

struct A {
    int x;
    A(int x_) : x(x_) {}
    A(A& other) : x(other.x) { }
    //^^ non-const ref cannot bind to rvalue.
    static A create() { return {12}; };
};

int main() {
    // Ill-formed before C++17 and guaranteed copy elision.
    A a1(A::create());  // (C++14) error: no matching constructor for initialization of 'A'
}
Run Code Online (Sandbox Code Playgroud)

[...] 为什么我们使用引用?

如果语言实际上允许将复制构造函数声明为通过值而不是引用获取其参数(例如,复制自对象),而不对语言进行任何其他更改,只需将复制自对象传递给复制构造函数(之前)实现它!)将需要从调用站点复制对象。因此,这样的复制构造函数需要在定义如何复制对象之前复制对象,这是一种自然不合理的递归逻辑。