Tutorial Study Image

C++ 拷贝构造函数


2023年1月19日, Learn eTutorial
1391

本教程将通过示例解释拷贝构造函数,以及它们的用途和如何在 C++ 中复制对象。

C++ 拷贝构造函数简介

拷贝构造函数是一种特殊的构造函数,主要用于创建现有类的对象的副本。具体来说,它将现有对象的成员变量值复制到新对象的成员变量中。

拷贝构造函数的基础知识

  • 在 C++ 中,拷贝构造函数是一个带参数的构造函数,用于初始化对象的副本。
  • 它使用旧对象的值来初始化新对象。
  • 拷贝初始化是主要使用拷贝构造函数来初始化对象成员的过程。
  • 拷贝构造函数使用一个现有对象(两者都属于同一个类)来初始化另一个对象,主要基于逐个成员的复制,这就是它也被称为成员式初始化的原因。
  • 拷贝构造函数可以由程序员显式定义。如果程序员不定义,编译器会定义拷贝构造函数。

拷贝构造函数的通用函数原型如下:

ClassName (const ClassName &old;_obj);

以下是定义和调用拷贝构造函数的语法:


//Definition
ClassName objectName (ClassName &existingObject;)
{
     Var1 = existingObject.Var1;
     Var2 = existingObject.Va2;
}

//Calling
ClassName ob1;
ClassName ob2(&ob1;);

 

让我们通过一个例子来理解语法:


#include <iostream>
using namespace std;

class Transport  
{  
   public:  
    int wheels;  
    string name;
    string type;
    string color;
    
    Transport(int n)                
    {  
      wheels=n;  
    }  
     Transport(Transport &ob;)           // a copy constructor is Defined
     {
         wheels=ob.wheels;
     }
     
};  

int main()  
{  
  Transport bike1(2);                  //  1st constructor  is Called
  Transport bike2(bike1);              //Method1 is calling a copy constructor
  Transport bike3=bike2;               //Method2 is calling a copy constructor
  cout<<"bike2 has "<<bike2.wheels<<" wheels \n";
  cout<<"bike3 has "<<bike3.wheels<<" wheels";

输出


bike2 has 2 wheels
bike3 has 2 wheels

在什么时候调用拷贝构造函数?

在以下情况下可能会调用 C++ 中的拷贝构造函数:

  • 当一个属于该类的对象通过值返回时。
  • 当一个类对象作为参数通过值传递给函数时。
  • 当基于属于同一个类的另一个对象形成一个对象时。
  • 当编译器创建一个临时对象时。

然而,不能保证在所有这些情况下都会调用拷贝构造函数,因为 C++ 标准允许编译器在某些情况下(例如返回值优化,即 RVO)消除复制。

返回值优化 (RVO):这是一种 C++ 编程语言中使用的编译器优化,用于消除存储函数返回值的临时对象。C++ 标准允许 RVO 改变生成程序的可见行为。

可以将拷贝构造函数设置为私有吗?

可以将拷贝构造函数设置为私有。当我们将类中的拷贝构造函数设置为私有时,该类中的所有对象都将无法复制。当我们的类包含指针或动态分配的资源(例如文件句柄、网络连接等)时,这非常有用。

拷贝省略是什么意思?

拷贝省略是 C++ 计算机编程中使用的一种编译器优化技术,它将防止未使用的对象复制。

在拷贝省略中,编译器会阻止创建不必要的或额外的副本,这既节省了空间,又将改善程序的复杂性(包括时间和空间)。因此,代码看起来更高效。

通常,C++ 语言标准允许实现使用任何优化,只要结果程序的可见行为与程序完全按照标准要求执行时的行为相同即可。除此之外,标准还概述了一些即使这样做可能会改变程序行为,也可以避免复制的情况。返回值优化就是最典型的例子。

例如,让我们编写一个 C++ 程序来理解 C++ 中拷贝省略的工作原理?


#include <iostream>
using namespace std;

class LeT {
public:
 void print() { cout << " Hai and hello friends!"; }
};

int main()
{
 LeT L;
 for (int i = 0; i <= 2; i++) {
  L.print();
 }
 return 0;
}

 

输出


 Hai and hello friends!
 Hai and hello friends!
 Hai and hello friends!

编译器现在必须选择打印什么;它可能会选择打印上面显示的结果或下面显示的两种情况之一。这被称为返回值优化。简单来说,返回值优化(RVO)是一种方法,它让编译器对终止生成的临时对象拥有更多控制权,从而影响最终程序的可见行为和属性。

情况 1
嗨,朋友们好!
嗨,朋友们好!
情况 2
嗨,朋友们好!

什么时候需要使用用户定义的拷贝构造函数?

对于每个类,如果我们不定义自己的拷贝构造函数,C++ 编译器会提供一个默认的拷贝构造函数,它在对象之间执行成员式复制。编译器生成的拷贝构造函数通常表现良好。如果对象具有指针或任何其他运行时资源分配(例如文件句柄、网络连接等),那么我们才需要定义自己的拷贝构造函数。

默认构造函数只执行浅拷贝。

C++ Copy Constructors

只有用户定义的拷贝构造函数才允许深拷贝。我们确保复制对象的指针(或引用)在用户定义的拷贝构造函数中指向新的内存位置。

C++ Copy Constructors

C++ 中拷贝构造函数的优点?

  • 使用拷贝构造函数可以简化对象复制。
  • 拷贝构造函数结合了构造和复制,比 copyfrom() 方法更有效。

C++ 中拷贝构造函数的缺点?

  • 在 C++ 中,对象隐式复制是错误和性能问题的一个来源。此外,它使遵循对象子例程的交付和更改变得更加困难,并使代码更难理解。
  • 只有少数类需要复制。大多数类不需要赋值运算符函数或拷贝构造函数。大多数情况下,使用指针或引用可以以更高的效率实现相同的目标。例如,与其通过值将参数传递给函数,不如通过引用或指针传递它们。
  • 如果你的类需要复制,你可以提供复制方法,如 CopyFrom() 或 clone(),而不是使用拷贝构造函数,因为编译器不能隐式使用此方法。
  • 如果你的类不需要复制构造函数和赋值运算符函数,则必须显式禁用它们。你可以通过在类的私有部分添加拷贝构造函数和赋值运算符函数的空声明(不包含任何相关定义)来实现此目的。因此,任何使用它们的尝试都会产生链接错误。