C++ 复制构造函数和构造函数的实现之间的区别

C++ 复制构造函数和构造函数的实现之间的区别,c++,copy-constructor,C++,Copy Constructor,复制构造函数的目的之一是使复制中声明的指针指向各自的成员,而不是简单地返回到原始成员,但这究竟是如何实现的 假设您的构造函数是: foo::foo(int i) { blah = i; bar = new whatever; //bar is a pointer to a whatever } 那么复制构造函数实现应该是什么样子呢?你唯一需要放进去的东西是: bar = this->whatever; 或 或者它应该包含普通构造函数所做的一切吗?不,复制构造函数是关于复

复制构造函数的目的之一是使复制中声明的指针指向各自的成员,而不是简单地返回到原始成员,但这究竟是如何实现的

假设您的构造函数是:

foo::foo(int i)
{
    blah = i;
    bar = new whatever; //bar is a pointer to a whatever
}
那么复制构造函数实现应该是什么样子呢?你唯一需要放进去的东西是:

bar = this->whatever;


或者它应该包含普通构造函数所做的一切吗?

不,复制构造函数是关于复制对象的成员,它与指针没有多大关系,除非成员是。例如,如果您有一个对象
x
y
成员,您将创建一个副本构造函数

point(const point& p) : x(p.x), y(p.y) { }
它可能有另一个构造函数,比如

point(int x_,int y_) : x(x_), y(y_) { }

如果您有一个指针成员,它取决于对象和您想要如何处理它-您可能想要复制指针或创建另一个指针,等等。这取决于它所指向的数据。

如果您没有复制构造函数,将为您创建一个默认构造函数,该构造函数执行浅复制,其中一个对象的每个成员变量只分配给另一个对象,而不是深度副本

因此,如果您有一个指向动态分配的缓冲区的指针,那么默认的复制构造函数将简单地将该指针分配给副本的指针,而不是创建它自己的
new
缓冲区来指向并将缓冲区的内容复制到新的缓冲区中。例如

class DynamicIntArray {
private:
   int *_array;
   size_t _size;

public:
   DynamicIntArray(size_t size) : _array(new int[size]), _size(size) { }

   DynamicIntArray (const DynamicIntArray &d) // copy constructor
   {
      delete[] _array;
      _array = new int[d._size];
      _size = d._size;
      std::copy(_array, d._array, d._array + d._size);
   }

   /* destructor, assignment operator, etc */
};
如果您没有创建默认的复制构造函数,那么创建的默认构造函数只会将
d.\u array
分配给
\u array
,这将导致严重的问题。也就是说,它可以替代上述功能:

_array = d._array;
_size = d._size;

请注意,如果您有一个复制构造函数,您可能应该有一个赋值运算符和一个析构函数(查找三个规则)。

这完全取决于
foo
是什么,以及它与
的关系

可能的选择包括:

共享对象

foo::foo(const foo& other) : blah(other.blah), bar(other.bar)
{ }
foo::foo(const foo& other) : blah(other.blah), bar(new whatever(*other.bar))
{ }
创建另一个对象

foo::foo(const foo& other) : blah(other.blah), bar(new whatever)
{ }
创建对象的新副本

foo::foo(const foo& other) : blah(other.blah), bar(other.bar)
{ }
foo::foo(const foo& other) : blah(other.blah), bar(new whatever(*other.bar))
{ }

我有一个指向成员的指针,如果我让编译器创建一个默认的复制构造函数,那么复制类中的指针将指向原始成员。我想让它指向它自己的成员。为什么?我最好的猜测是坐标,但没关系。它可能是一个包含实部和虚部的复数,它可能是一个字符串,它可能是一个人和一个人的智商,它可能是一个开发人员,他能流利地使用一系列编程语言,等等。这不正是默认复制构造函数所做的吗?为什么我会这样做,当我添加了另一个成员并忘记相应地更改复制构造函数时,可能会引入一个bug?这取决于对象。您可能希望为对象或其他对象添加一些生存历史记录…您不一定要复制所有成员。此线程解释了需要如何实现它。如果我要为一个类编写一个复制构造函数,我肯定想看看这个类的定义。它会将原始指针分配给这个复制?你确定吗?@SirYakalot:如果你使用默认的复制构造函数,那么它只需执行
\u array=d.array。我想你可以看出问题所在。这个答案有什么问题吗?我认为它回答了OP关于如何实现复制构造函数的问题。:)但是有了所有这些,所有原始foo的成员都会被复制,除非您对它们做了一些特定的操作?或者您必须列出每个要复制的成员吗?因此
foo
有两个以上的成员吗?:-)您必须决定创建副本的意义。如果添加复制构造函数,则该构造函数将精确决定对象的复制方式。如果没有,编译器只会创建一个默认的(成员方面的)副本。因此,如果foo有许多成员,并且希望副本具有相同的成员,则必须在复制构造函数中列出所有成员。是这样吗?成员功能如何?默认情况下它们都存在吗?