Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
复制构造函数的用途是什么,而赋值运算符'=';? 为什么C++提供了拷贝构造函数?赋值运算符可以执行相同的任务。复制构造函数比赋值运算符有什么优势吗?_C++_Oop_Copy Constructor - Fatal编程技术网

复制构造函数的用途是什么,而赋值运算符'=';? 为什么C++提供了拷贝构造函数?赋值运算符可以执行相同的任务。复制构造函数比赋值运算符有什么优势吗?

复制构造函数的用途是什么,而赋值运算符'=';? 为什么C++提供了拷贝构造函数?赋值运算符可以执行相同的任务。复制构造函数比赋值运算符有什么优势吗?,c++,oop,copy-constructor,C++,Oop,Copy Constructor,无论是否有复制构造函数,您仍然必须将新对象初始化为稳定的初始状态,赋值运算符随后可以更新该状态 虽然您当然可以在没有复制构造函数的情况下实现这一点,但拥有复制构造函数有助于优化新对象的初始化,方法是预先将其设置为复制另一个对象的状态,而不需要您首先将新对象初始化为默认状态,然后再进行单独的赋值来重置该状态。这样,您就可以在1次操作而不是2次操作中设置新对象的状态。是的,这两次操作是不同的。您不能总是将复制构造函数实现为 Foo(const Foo& f) { *this = f;

无论是否有复制构造函数,您仍然必须将新对象初始化为稳定的初始状态,赋值运算符随后可以更新该状态


虽然您当然可以在没有复制构造函数的情况下实现这一点,但拥有复制构造函数有助于优化新对象的初始化,方法是预先将其设置为复制另一个对象的状态,而不需要您首先将新对象初始化为默认状态,然后再进行单独的赋值来重置该状态。这样,您就可以在1次操作而不是2次操作中设置新对象的状态。

是的,这两次操作是不同的。您不能总是将复制构造函数实现为

Foo(const Foo& f) {
    *this = f;
}

赋值运算符假定您有一个有效的、完全构造的对象。复制构造函数不做这样的假设。这意味着,根据您的类,赋值运算符可能会在重新初始化之前尝试清除对象上的任何数据。或者甚至可以重新调整对象上已有数据的用途。

使用复制构造函数可以完成的事情,而使用赋值运算符则无法(轻松或根本无法)完成:

  • 复制没有默认构造函数的类。例如,如果一个类表示一个打开的文件,您可能无法在不向其传递要打开的文件名的情况下构造一个文件

  • 复制具有昂贵的默认构造函数的类。可能构造函数分配了大量内存,当您使用赋值操作符将新状态复制到对象中时,这些内存就会被释放

  • 按值传递类的实例。这是复制构造函数的原始用途。在C语言中,如果按值传递结构,编译器只需对结构进行逐位复制,以便接收函数有一个本地副本,可以在不影响调用方的情况下进行修改。但是C++认识到,位拷贝不是复制大多数对象的最佳方式,因此它允许您编写自己的复制构造函数(并且默认复制行为也不同,因为类成员可能有自定义复制构造函数)。
  • 复制包含引用的类,因为在已构造该类后无法重新分配引用。复制构造函数和赋值运算符只是在涉及引用时执行不同的操作。复制构造函数初始化引用,使其指向被复制实例中引用指向的同一对象;赋值运算符实际上复制引用对象的值

  • 复制具有常量成员的类。(请注意,类可以有默认构造函数,但仍然有const成员。)

  • 就拿这个例子来说

    杰克和约翰是双胞胎。 你可以说这是杰克,那是杰克。 虽然约翰是杰克的化身,但他不是杰克

    使用赋值运算符时,可以引用内存中的确切对象(返回*this)或提供一些自定义行为

    使用复制构造函数时,您希望在内存中创建另一个对象,该对象具有原始对象属性的副本,但可以朝不同的方向发展

    如果你想得到一个更深刻的答案,我认为更好

    赋值比初始化要复杂一点,因为 我们基本上是在破坏现有的物体,然后 用新的价值观重新构建它。在更复杂的类中,您可能 需要释放各种资源,然后使用副本重新分配它们 正在复制的对象中的资源。std::唯一的ptr 我们的生活在这里很轻松,因为分配了一个新的 std::unique_ptr到一个现有的std::unique_ptr对象,使用=如上所述 (或使用reset())首先释放旧指针,因此释放 资源是自动为我们处理的(这与我们的 类不需要析构函数–当std::unique_ptr超出 作用域当对象超出作用域时,std::unique_ptr的析构函数 调用并自动释放资源)


    您将如何
    Foo复制(源代码)没有复制构造函数?没有复制构造函数也很难传递值。@NathanOliver我认为OP要求的是
    Foo copy(source)的区别/好处vs
    Foo复制;拷贝=源复制构造函数可以是深度复制,而赋值运算符可以用于分配内存地址这是否回答了您的问题?通常,应该实现赋值运算符来使用复制构造函数,而不是相反。绝对是@Remy。可能是这里提到的工作。@RemyLebeau,如果这个类是抽象的,我不想将实现转移到派生类中怎么办?一个抽象类仍然可以有构造函数和赋值运算符,哪些派生类可以根据需要调用。@RemyLebeau如果我想将所有复制构造代码放入已经有赋值运算符的基类中,我可以使用
    *this=f构造函数的类型。然而,我不能通过复制构造来执行任务。问题是这个问题是否有一些惯用的解决方案。关于第4点,复制通过引用构造的类也是复制可分配的,这不是一个坏主意吗?可能。我试着想一个例子,在这个例子中,你想这样做,但实际上什么都不想出来。Re 2:你在那里掉了一个“高效”的词,因为这肯定是可能的,尽管是浪费。我试着用“要么容易,要么根本不”的评论来掩盖这一点。也可以通过丢弃常量来分配具有常量成员(#5)的类,或者分配一个对象而不调用其构造函数,然后对其赋值。这不是一个好主意。这在中国是不正确的