运算符重载——拷贝构造函数与赋值运算符的区别、如何实现赋值运算符的深拷贝

本文深入解析C++中拷贝构造函数与赋值运算符的区别,阐述在不同场景下如何调用二者,并详细讲解实现赋值运算符深拷贝的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录:
写在前面

1)C++的编译器会默认给一个类提供4个函数

  1. 默认构造函数(无参、函数体为空)
  2. 默认析构函数(无参、函数体为空)
  3. 默认拷贝函数(浅拷贝,对属性仅进行值拷贝)
  4. 赋值运算符operator=(对属性进行值拷贝)

我们知道类中的默认拷贝构造函数赋值运算符,都是对属性进行值拷贝,但是它们之间有什么区别吗?在什么情况下会调用它们?下面会详细介绍.

2)本篇涉及内容:

  • 拷贝构造函数和赋值运算符的区别
  • 如何实现赋值运算符的深拷贝
拷贝构造函数和赋值运算符

在这里插入图片描述
从上面代码我们可以知道

  • 默认的拷贝构造函数和赋值运算符重载都是对属性进行简单的值拷贝(浅拷贝),如果属性中有涉及到堆内存的使用需要进行函数重写

那么在什么情况下会调用拷贝构造函数和赋值运算符重载

  • 调用拷贝构造函数的情况:

    1. 通过一个已存在的对象来构造一个新的对象,此时会调用这个新对象的拷贝构造函数.

    2. 当一个对象作为函数实参传入时,此时会调用形参的拷贝构造函数.

    3. 当函数的返回值是一个对象时,此时接受这个函数返回值的对象会调用拷贝构造函数.

      从上面的情况我们可以总结出:
      当一个已经构造好了的对象去赋值给一个还未构造的对象,此时就会调用这个还未构造的对象的拷贝构造函数,产生的结果是会有新的对象产生.

      关于深浅拷贝和拷贝构造函数的详细介绍请看:C++的堆与拷贝构造函数

  • 调用赋值运算符重载的情况:

    1. 两个对象已经存在,用对象p1去重新赋值给另一个对象p2即p2 = p1,此时会调用p2对象的运算符重载.

      从上述情况我们可以得出:
      当一个已经构造好了的对象去重新赋值给另一个构造好了的对象,此时就会调用这个被赋值的对象的运算符重载,这个过程中没有新对象产生.

实现赋值运算符重载的深拷贝

在这里插入图片描述
下面仔细来看一下实现赋值运算符重载的深拷贝代码

	Person& operator= (Person& p) {

		//先判断原来的对象是否存在堆区
		if (this->m_Age != NULL) {
			delete this->m_Age;
			this->m_Age = NULL;
		}

		//深拷贝
		this->m_Age = new int(*p.m_Age);

		//返回对象本身
		return *this;
	}

我们可以看见,实现深拷贝的原理和实现拷贝构造函数深拷贝的原理相同,但是这里需要注意的是:

  • 进行深拷贝之前要先把原来已经存在的堆内存释放掉
  • 返回值是当前对象本身的引用
### C++ 中拷贝构造函数赋值操作符重载区别 #### 拷贝构造函数 当创建一个新的对象并初始化它为另一个同类型对象的时候,会调用拷贝构造函数。如果类中没有显式定义拷贝构造函数,则编译器提供默认版本[^4]。 对于自定义资源管理(比如动态分配内存),通常需要编写自己的拷贝构造函数来执行深拷贝而不是简单的位复制(即浅拷贝)。这可以防止多个对象共享同一块堆内存放的数据而导致潜在的风险错误。 ```cpp class MyClass { public: int* data; // 构造函数 MyClass(int value) : data(new int(value)) {} // 拷贝构造函数 MyClass(const MyClass& other) : data(new int(*other.data)) {} // 执行深拷贝 ~MyClass() { delete data; } }; ``` #### 赋值操作符重载 而赋值操作符用于已经存在的对象之间相互赋值的情况。同样地,默认情况下编译器提供了基本功能;但是为了处理复杂情况下的正确性效率问题,可能也需要手动实现这个过程——特别是涉及到动态内存或其他形式外部资源的情况下: - 需要释放当前持有的资源; - 复制源对象的内容到目标对象上; - 返回`*this`以便支持链式表达式的使用方式。 ```cpp class MyClass { public: int* data; // ...其他成员... // 赋值操作符重载 MyClass& operator=(const MyClass& rhs) { if (this != &rhs) { // 自我赋值检查 *data = *(rhs.data); // 进行必要的清理工作以及新数据的复制 } return *this; // 支持连续赋值语句 } private: }; ``` #### 主要区别 1. **生命周期阶段不同** - 拷贝构造发生在对象创建之时。 - 赋值则是在两个已有的对象间交换状态之后发生。 2. **作用域差异** - 前者仅限于构造期间有效。 - 对于赋值来说非常重要,因为可能存在同一个对象给自己赋值的情形。 - 拷贝构造不存在这种情况,因为它总是在构建全新的实例时触发。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值