C++ 拷贝构造函数与赋值运算符重载详解
引言
在 C++ 面向对象编程中,对象的复制操作无处不在。无论是函数传参、返回值传递,还是对象间的赋值,都需要精确控制数据的复制行为。
C++ 通过拷贝构造函数和赋值运算符重载两套机制,为开发者提供了对象复制的完整解决方案。本文将从基础概念出发,深入解析这两种复制机制的实现细节与应用技巧。
一、拷贝构造函数
如果一个构造函数的第一个参数是自身类型的引用,且 其他所有参数都有默认值(如果有) ,就叫做 拷贝构造,是特殊的构造函数。
- 基本形式:
#include <iostream>
using namespace std;
// 基本形式
class Example {
public:
Example(Example& d) {
// ...
}
};
1.1 解析:拷贝构造特点
(部分规则与构造函数相同)
- 拷贝构造函数是构造函数的一个重载;
- 拷贝构造函数的第一个参数必须是自身类类型的引用:类名& 或 const 类名&(最好加
const)。 如果使用传值的方式,在逻辑上会引发无穷递归调用; - 拷贝构造函数可以有多个参数,第一个为引用,其他必须有缺省值;
- C++ 规定自定义类型对象进行拷贝行为必须调用拷贝构造,所以这里自定义类型传值传参和传值返回都会调用拷贝构造完成;
- 若未显式定义拷贝构造,编译器会生成自动生成拷贝构造函数。默认生成的拷贝构造对内置类型成员变量会完成值拷贝/浅拷贝(⼀个字节⼀个字节的拷贝),对自定义类型成员变量会调用他的拷贝构造;
- 类似前面说的
Date类,成员变量全是内置类型且不指向资源,编译器默认生成的拷贝构造就够了。类似Stack类,虽然也都是内置类型,但是指针指向资源,那么编译器默认生成的浅拷贝/值拷贝就不太够,需要显式定义深拷贝。再对于MyQueue类,自定义类型Stack变量成员就直接调用它的拷贝构造。
【技巧】:如果一个类显式实现了析构并释放资源,那么他就需要显式定义深拷贝,否则就不需要。
- 传值返回会产生一个临时对象来调用拷贝构造;而传引用返回,返回的是对象的别名,不会产生拷贝,但是返回的对象为一个当前函数局部域的局部对象,函数结束就会销毁,这时传引用返回是有问题的,类似于野指针。 (传引用返回会减少拷贝,但是要确保返回对象在函数结束时不会被销毁)
解释特点第 2 条:
当拷贝构造函数传值传参时,函数的形参是实参拷贝出来的新对象,要调用拷贝构造,但是拷贝构造函数也是传值传参就又要调用拷贝构造,这样无限循环下去……
其次,在引用传参最好加上 const,因为将对象传过来,也不会将对象进行改变操作,那么 const 就方便了传参(权限缩小)。当然,这时候传 const 对象也是可以的(权限平移)。
- 特点第 2 条拓展:既然要引用传参,那么指针可以吗? 先说,传指针是可以的,但是函数就变成普通的构造函数,不是拷贝构造函数。


