当我们将对象作为参数传递给方法时,为啥会调用复制构造函数?

Posted

技术标签:

【中文标题】当我们将对象作为参数传递给方法时,为啥会调用复制构造函数?【英文标题】:Why is the copy constructor called when we pass an object as an argument by value to a method?当我们将对象作为参数传递给方法时,为什么会调用复制构造函数? 【发布时间】:2013-05-19 16:04:17 【问题描述】:

当我将对象作为参数按值传递给函数时,为什么会调用复制构造函数?请看我下面的代码:我将一个类的对象作为值作为参数传递给函数display(),但它在控制到达display() 函数之前调用了复制构造函数。我不明白为什么。

#include "stdafx.h"
#include <iostream>
using namespace std;

class ClassA

    private:
       int a, b;
    public:
       ClassA()
       
           a = 10, b = 20;
       
       ClassA(ClassA &obj)
       
           cout << "copy constructor called" << endl;
           a = obj.a;
           b = obj.b;
       
;
void display(ClassA obj)

   cout << "Hello World" << endl;

int main()

   ClassA obj;
   display(obj);
   return 0;

【问题讨论】:

【参考方案1】:

详细说明已经给出的两个答案:

当您将变量定义为“与”某个其他变量“相同”时,您基本上有两种可能性:

ClassA aCopy = someOtherA; //copy
ClassA& aRef = someOtherA; //reference

除了非 const 左值引用,当然还有 const 引用和右值引用。这里我要指出的主要一点是,aCopy 独立于someOtherA,而aRef 实际上与someOtherA 是同一个变量,只是它的另一个名称(别名)。

有了函数参数,基本一样。当参数是引用时,它会在调用函数时绑定到参数,并且它只是该参数的别名。这意味着,你对参数做什么,你对参数做什么:

void f(int& iRef) 
  ++iRef;


int main() 
  int i = 5;
  f(i); //i becomes 6, because iRef IS i

当参数是一个值时,它只是参数的一个副本,所以无论你对参数做什么,参数都保持不变。

void f(int iCopy) 
  ++iCopy;


int main() 
  int i = 5;
  f(i); //i remains 5, because iCopy IS NOT i

按值传递时,参数是一个新对象。它必须是,因为它与论点不同,它是独立的。创建一个作为参数副本的新对象意味着调用复制构造函数或移动构造函数,具体取决于参数是左值还是右值。 在您的情况下,使函数按值传递是不必要的,因为您只读取参数。

有一个来自GotW #4的指南:

如果您只想从中读取(而不是复制它),最好通过 const& 传递只读参数。

【讨论】:

【参考方案2】:

因为按值传递给函数意味着该函数有它自己的对象的副本。为此,调用了复制构造函数。

void display(ClassA obj)

   // display has its own ClassA object, a copy of the input
   cout << "Hello World" << endl;

请记住,在某些情况下,副本可能会被省略,例如,如果将临时值传递给函数。

【讨论】:

【参考方案3】:

正如 juanchopanza 所说:您按值传递,这会导致复制。如果你想防止这种情况,你可以通过引用传递:

void display(const ClassA &obj)

附带说明:您应该声明您的复制 ctor 以将参数作为 const 引用:

ClassA(const ClassA &obj)

否则,您将无法在标记为 const 或临时对象的命名对象上使用复制 ctor。它还可以防止您意外更改传入的对象。

【讨论】:

以上是关于当我们将对象作为参数传递给方法时,为啥会调用复制构造函数?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我们将字符串数组作为参数传递给 main() 方法,为啥不传递任何集合类型或包装类型或原始类型?

我可以将数组和变量作为参数传递给 C# 中的方法吗? [复制]

如何将类对象作为参数传递给不同的类方法?

将对象作为参数传递给构造函数并将其属性复制到新对象?

如何将复杂的 Java 类对象作为参数传递给 Spark 中的 Scala UDF?

为啥这个函数调用后数组会改变? [复制]