【问题标题】:Why do we use const and reference for arguments to copy constructors?为什么我们使用 const 和 reference 作为参数来复制构造函数?
【发布时间】:2020-11-05 14:04:45
【问题描述】:

考虑以下示例:

#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;
}

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

【问题讨论】:

  • 一个原因是临时对象不能绑定到非常量引用。
  • 注意:我已经恢复了 OP:s 编辑,它添加了一个完全独立的问题。 OP:请仅针对每个线程提出问题。

标签: c++ class constructor


【解决方案1】:

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

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

T的复制构造函数是一个非模板构造函数,它的第一个参数是T&amp;‍const T&amp;‍volatile T&amp;‍const volatile T&amp;‍,或者没有其他参数,或者剩下的参数都有默认值。

但如果复制构造函数需要变异它用于复制的对象,那将是非常不寻常的

#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
}

此外,非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.
}

而以下是格式错误的(在 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'
}

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-12-05
    • 2017-03-26
    • 1970-01-01
    • 2013-06-02
    • 2013-08-24
    • 2022-01-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多