为啥复制构造函数应该在 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);
即复制carobj
到c
。
carobj
需要复制到函数f
中的参数c
中。
为了实现复制,调用了复制构造函数。
在这种情况下,函数f
使用传值调用,换句话说,函数f
被声明为传值。
如果函数f
通过引用传递,那么它的声明是
int f(car &c);
在这种情况下,car carobj;
f(carobj);
不需要复制构造函数。
在这种情况下,c
成为carobj
的别名。
使用上述 2 个场景,为清楚起见,我将它们总结为:
如果函数被声明为将参数作为对象的值,则调用该对象的复制构造函数。
如果函数被声明为将参数作为“按引用传递”,则该参数将成为调用者提供的对象的别名。不需要复制构造函数!
现在的问题是为什么需要通过引用传递。如果复制构造函数接受引用,则接收变量将成为所提供对象的别名。因此,不需要复制构造函数(在这种情况下,调用自身)将调用者提供的对象中的值复制到参数列表中的构造函数变量。
否则,如果复制构造函数将调用者提供的对象作为值,即按值传递,那么它需要给定对象的复制构造函数;因此,要将调用者提供的对象获取到我们的函数本身(在本例中为复制构造函数),我们需要调用复制构造函数,这只不过是在函数声明期间调用相同的函数。
这就是将引用传递给复制构造函数的原因。
【讨论】:
虽然你是对的,但已经有四个答案解释了这一点,而且做得更清楚。我不明白你为什么认为这个问题的第五个答案会有帮助。【参考方案6】:必须将对象作为引用而不是按值传递,因为如果按值传递它,则它的副本是使用复制构造函数构造的。这意味着复制构造函数将调用自己进行复制。这个过程将一直持续到编译器内存不足。
【讨论】:
【参考方案7】:将对象作为引用传递是非常重要的。如果一个对象作为值传递给复制构造函数,那么它的复制构造函数将调用自身,将实际参数复制到形式参数。 因此,将启动对复制构造函数的无限调用链。这个过程会一直持续到系统内存不足。
因此,在复制构造函数中,参数应始终作为引用传递。
【讨论】:
【参考方案8】:如果它不是按引用传递,那么它将按值传递。如果参数是按值传递的,它的复制构造函数会调用自己将实参复制到形参。这个过程会一直持续到系统内存不足。 所以,我们应该通过引用传递它,这样复制构造函数就不会被调用。
【讨论】:
【参考方案9】:复制构造函数定义了复制的含义,所以如果我们只传递一个对象(我们将传递该对象的副本)但要创建副本,我们将需要一个复制构造函数,因此它会导致无限递归。
所以,复制构造函数必须有一个引用作为参数。
【讨论】:
以上是关于为啥复制构造函数应该在 C++ 中通过引用来接受它的参数?的主要内容,如果未能解决你的问题,请参考以下文章