复制构造函数和复制赋值运算符 (C++)
注意
从 C++11 中开始,该语言支持两类赋值:复制赋值和移动赋值。 在本文中,“赋值”意味着复制赋值,除非有其他显式声明。 有关移动赋值的信息,请参阅移动构造函数和移动赋值运算符 (C++)。
赋值操作和初始化操作都会导致对象被复制。
赋值:将一个对象的值分配给另一个对象时,第一个对象将复制到第二个对象。 因此,此代码将
b
的值复制到a
:Point a, b; ... a = b;
初始化:在声明新对象、按值传递函数参数或从函数返回值时,将发生初始化。
您可以为类类型的对象定义“复制”的语义。 例如,假设有以下代码:
TextFile a, b;
a.Open( "FILE1.DAT" );
b.Open( "FILE2.DAT" );
b = a;
前面的代码可能表示“将 FILE1.DAT 的内容复制到 FILE2.DAT”,也可能表示“忽略 FILE2.DAT 并使 b
成为 FILE1.DAT 的另一个句柄”。必须将合适的复制语义附加到每个类,如下所示:
使用返回对类类型的引用的赋值运算符
operator=
,并采用const
引用传递的一个参数,例如ClassName& operator=(const ClassName& x);
。使用复制构造函数。
如果不声明复制构造函数,编译器将为你生成成员的复制构造函数。 同样,如果不声明复制赋值运算符,编译器将为你生成成员的复制赋值运算符。 声明复制构造函数不会取消编译器生成的复制赋值运算符,反之亦然。 如果实现其中任一方法,我们建议也实现另一个。 实现这两者时,代码的含义是明确的。
复制构造函数采用 ClassName&
类型的参数,其中 ClassName
是类的名称。 例如:
// spec1_copying_class_objects.cpp
class Window
{
public:
Window( const Window& ); // Declare copy constructor.
Window& operator=(const Window& x); // Declare copy assignment.
// ...
};
int main()
{
}
注意
尽可能创建复制构造函数的参数 const ClassName&
的类型。 这可防止复制构造函数意外更改复制的对象。 它还允许从 const
对象复制。
编译器生成的构造函数
编译器生成的复制构造函数(如用户定义的复制构造函数)具有单个自变量类型“对 class-name 的引用”。当所有基类和成员类都具有声明为采用 const
class-name& 类型的单个自变量的复制构造函数时,将引发异常。 在这种情况下,编译器生成的复制构造函数的自变量也是 const
。
当复制构造函数的自变量类型不是 const
时,复制 const
对象进行初始化将产生错误。 反之则不然:如果自变量是 const
,可以复制不是 const
的对象进行初始化。
编译器生成的赋值运算符遵循 const
的相同模式。 除非所有基类和成员类中的赋值运算符都采用 const ClassName&
类型的自变量,否则它们将采用 ClassName&
类型的单个自变量。 在这种情况下,类的生成的赋值运算符采用 const
自变量。
注意
当虚拟基类由复制构造函数(编译器生成或用户定义的)初始化时,将只初始化一次:在构造它们时。
含义类似于复制构造函数的含义。 当自变量类型不是 const
时,从 const
对象赋值将产生错误。 反之则不然:如果将 const
值赋给不是 const
的值,则赋值能成功。
有关重载赋值运算符的详细信息,请参阅赋值。
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈