为什么在这个例子中调用复制构造函数

Why was copy constructor called in this example?

本文关键字:调用 复制 构造函数 为什么      更新时间:2023-10-16

我是c++的新手,我不明白为什么在下面的代码中调用复制构造函数:

 #include <iostream>
    using namespace std;
    class Line
{
   public:
      int getLength( void );
      Line( int len );             // simple constructor
      Line( const Line &obj);  // copy constructor
      ~Line();                     // destructor
   private:
      int *ptr;
};
// Member functions definitions including constructor
Line::Line(int len)
{
    cout << "Normal constructor allocating ptr" << endl;
    // allocate memory for the pointer;
    ptr = new int;
    *ptr = len;
}
Line::Line(const Line &obj)
{
    cout << "Copy constructor allocating ptr." << endl;
    ptr = new int;
   *ptr = *obj.ptr; // copy the value
}
Line::~Line(void)
{
    cout << "Freeing memory!" << endl;
    delete ptr;
}
int Line::getLength( void )
{
    return *ptr;
}
void display(Line obj)
{
   cout << "Length of line : " << obj.getLength() <<endl;
}
// Main function for the program
int main( )
{
   Line line(10);
   display(line);
   return 0;
}

运行时:

Normal constructor allocating ptr
Copy constructor allocating ptr.
Length of line : 10
Freeing memory!
Freeing memory!

为什么用简单构造函数在第一个对象之后构造另一个Line对象?

谢谢!

因为您将Line作为值传递

void display(Line obj)
{
   cout << "Length of line : " << obj.getLength() <<endl;
}

你应该把它作为常量引用传递,这样更快(display应该是一个常量方法,所以常量对象可以调用它)。

void display(const Line &obj) const
{
   cout << "Length of line : " << obj.getLength() <<endl;
}

(如果改成int getLength( void ) const;)

在你的例子中,考虑重新定义赋值运算符
Line &operator=(const Line &other);

或影响另一行将复制指针数据,并在第二次删除对象时崩溃,因为内存将被释放两次。

如果你想确保默认复制构造函数/赋值操作符不能被调用,只需在私有部分声明它们:

private:
  Line &operator=(const Line &other);
  Line(const Line &other);

使用它们的代码将无法编译。

您的display函数采用Line的值-这意味着该函数获得自己的副本。如果您不希望这样做,请传递(const)引用或指针。

答案在这里:

void display(Line obj) { ...

函数obj的参数是按值传递的。

因此,当调用函数时,将调用函数传递给的实参复制

为了给你一个简单的解释,想象一下:

function:main (caller) -> 
make a copy of line ->
call the function display (callee) which is going to use the copy made by caller.

该策略在各种情况下使用,例如:

  • 确保被调用函数将对调用者的变量产生任何影响(副作用)。
  • 当被调用函数将执行对象的副本时,因此您可以避免在主体函数中进行复制。

由于按值传递实参将执行实参本身的复制,因此最好使用通过引用传递的实参

这是一个例子:

void display(Line& obj) { ...

在这种情况下,它将不执行对象的副本,但参数obj将是对调用函数传递的参数的引用(如指针)。

综上所述,通过引用传递允许被调用函数产生副作用,即被调用函数可以修改调用函数拥有的变量

复制构造函数在以下情况下被调用:

(a),当函数返回该对象时按值分类

(b)当该类的对象经过时值作为函数的参数

(c)当你基于另一个对象构造一个对象时对象

(d)当编译器生成临时对象并使用类对象初始化时。

在你的代码中,你通过值传递类的对象作为函数的参数希望能有所帮助