为啥复制构造函数应该在 C++ 中通过引用来接受它的参数?

Posted

技术标签:

【中文标题】为啥复制构造函数应该在 C++ 中通过引用来接受它的参数?【英文标题】:Why should the copy constructor accept its parameter by reference in C++?为什么复制构造函数应该在 C++ 中通过引用来接受它的参数? 【发布时间】:2011-02-10 18:24:23 【问题描述】:

为什么复制构造函数的参数必须通过引用传递?

【问题讨论】:

【参考方案1】:

因为如果不是通过引用,它就是通过值。为此,您制作一个副本,并为此调用复制构造函数。但要做到这一点,我们需要创建一个新值,所以我们调用复制构造函数,等等......

(您将有无限递归,因为“要复制,您需要复制”。)

【讨论】:

是否有原因不能将指针传递给实例? 那么它就不再是拷贝构造函数了,而只是一个普通的旧构造函数,恰好接受了一个指针。 @Barry 当编译器尝试通过调用object o(other_object) 自行复制对象时,您通常会实现一个复制构造函数。但这只适用于object 有一个构造函数,该构造函数通过值或引用获取另一个object。您已经知道为什么按值传递不起作用,所以唯一的方法是按引用或 const 引用传递。如果您的“复制构造函数”需要一个指向object 的指针,那么编译器的代码必须是object o(&other_object)。所以本质上你编写了一个满足编译器和用户期望的构造函数。 是的,这完全有道理。谢谢。 我的编译器指出的另一个很好的理由是,如果您有一个带有纯虚函数的基类,则不可能按值初始化此变量【参考方案2】:

因为按值传递会调用复制构造函数:)

【讨论】:

【参考方案3】:

传递引用的替代方法是传递值。 Pass-by-value 实际上是 pass-by-copy。需要复制构造函数来制作副本。

如果您必须制作副本只是为了调用复制构造函数,那将是一个难题。

(我认为无限递归会发生在编译器中,你永远不会真正得到这样的程序。)

除了合理的原因,§12.8/3 中的标准禁止这样做:

a 的构造函数声明 类 X 是非良构的,如果它的第一个 参数的类型(可选 cv- 合格)X 并且要么没有 其他参数或所有其他 参数有默认参数。

【讨论】:

编译器可以愉快地吐出无限递归;我怀疑这不是特例。但是,如果您声明带有非引用参数的复制构造函数,则该程序是格式错误的。所以你是对的,它不应该编译。 @Dennis:我的意思是,如果您尝试编译这样的程序,编译器会在尝试生成代码时卡住。它不会生成递归函数,因为难题发生在函数调用之前,在调用者中。 无论您是否尝试使用,该程序都是错误的。简单地定义构造函数就足以让编译器对你大喊大叫。 @Dennis:确实,虽然这只是一个规则。【参考方案4】:

如果按值传入会无限递归

【讨论】:

【参考方案5】:

每当您调用函数时(例如:int f(car c)) 它采用除内置数据类型以外的参数(此处为 car) 复制调用者提供的实际对象的要求 到被调用函数参数中的变量。 示例:

car carobj; f(carobj);

即复制carobjc

carobj需要复制到函数f中的参数c中。

为了实现复制,调用了复制构造函数。

在这种情况下,函数f使用传值调用,换句话说,函数f被声明为传值。

如果函数f通过引用传递,那么它的声明是 int f(car &c);

在这种情况下,car carobj; f(carobj);

不需要复制构造函数。

在这种情况下,c 成为carobj 的别名。

使用上述 2 个场景,为清楚起见,我将它们总结为:

    如果函数被声明为将参数作为对象的值,则调用该对象的复制构造函数。

    如果函数被声明为将参数作为“按引用传递”,则该参数将成为调用者提供的对象的别名。不需要复制构造函数!

现在的问题是为什么需要通过引用传递。如果复制构造函数接受引用,则接收变量将成为所提供对象的别名。因此,不需要复制构造函数(在这种情况下,调用自身)将调用者提供的对象中的值复制到参数列表中的构造函数变量。

否则,如果复制构造函数将调用者提供的对象作为值,即按值传递,那么它需要给定对象的复制构造函数;因此,要将调用者提供的对象获取到我们的函数本身(在本例中为复制构造函数),我们需要调用复制构造函数,这只不过是在函数声明期间调用相同的函数。

这就是将引用传递给复制构造函数的原因。

【讨论】:

虽然你是对的,但已经有四个答案解释了这一点,而且做得更清楚。我不明白你为什么认为这个问题的第五个答案会有帮助。【参考方案6】:

必须将对象作为引用而不是按值传递,因为如果按值传递它,则它的副本是使用复制构造函数构造的。这意味着复制构造函数将调用自己进行复制。这个过程将一直持续到编译器内存不足。

【讨论】:

【参考方案7】:

将对象作为引用传递是非常重要的。如果一个对象作为值传递给复制构造函数,那么它的复制构造函数将调用自身,将实际参数复制到形式参数。 因此,将启动对复制构造函数的无限调用链。这个过程会一直持续到系统内存不足。

因此,在复制构造函数中,参数应始终作为引用传递。

【讨论】:

【参考方案8】:

如果它不是按引用传递,那么它将按值传递。如果参数是按值传递的,它的复制构造函数会调用自己将实参复制到形参。这个过程会一直持续到系统内存不足。 所以,我们应该通过引用传递它,这样复制构造函数就不会被调用。

【讨论】:

【参考方案9】:

复制构造函数定义了复制的含义,所以如果我们只传递一个对象(我们将传递该对象的副本)但要创建副本,我们将需要一个复制构造函数,因此它会导致无限递归。

所以,复制构造函数必须有一个引用作为参数。

【讨论】:

以上是关于为啥复制构造函数应该在 C++ 中通过引用来接受它的参数?的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 PHP 中通过引用传递?

在 C++ 中通过引用与按值将向量传递给函数

在 C++ 中通过构造函数复制类

尝试在 C++ 中通过引用乘以矩阵时出现访问冲突异常

在python中通过引用传递引用

在 C++ 中通过引用和值传递字符串