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

3 回答 3

22

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

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

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& 传递只读参数。

于 2013-05-24T06:28:57.300 回答
6

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

void display(ClassA obj)
{
   // display has its own ClassA object, a copy of the input
   cout << "Hello World" << endl;
}

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

于 2013-05-24T05:52:05.977 回答
5

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

void display(const ClassA &obj)

在旁注中:您应该声明您的复制 ctor 以将参数作为 const 引用:

ClassA(const ClassA &obj)

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

于 2013-05-24T06:05:57.820 回答