C++“拷贝构造函数”与“等号=赋值运算符重载函数”的使用注意事项

news/2024/11/23 0:39:13/

文章目录


本文主要搞清楚以下两种写法区别:(看不懂的话可以把 *p_m1换成 m1

  1. 拷贝构造函数
MyClass m2(*p_m1);	// 或:MyClass m2 = *p_m1;
  1. 等号=赋值运算符重载函数
MyClass m2;
m2 = *p_m1;

先看一段代码:

#include <iostream>
#include <cstdlib>
#include <limits>
#include <string>
using namespace std;class MyClass
{
public:int *ptr;MyClass(){ptr = new int[10];}~MyClass(){delete[] ptr;}MyClass(const MyClass &other) // 拷贝构造函数 //写了这个不用写重载等号代码,调用MyClass m1 = m2;相当于调用了拷贝构造函数{ptr = new int[10];for (int i = 0; i < 10; i++){ptr[i] = other.ptr[i];}}
};int main()
{int *p_int;// MyClass m1;MyClass *p_m1 = new MyClass(); // 创建对象p_int = p_m1->ptr;for (auto i = 0; i < 10; i++){p_m1->ptr[i] = i;}*p_int = 111;for (auto i = 0; i < 10; i++){cout << p_m1->ptr[i] << endl;}MyClass m2 = *p_m1; //没问题    //这个调用了我们上面实现的拷贝构造函数,我把拷贝构造函数注释掉之后就不行了(变成浅拷贝)// MyClass m2; // 段错误   //free(): double free detected in tcache 2 //Aborted (core dumped)  /浅拷贝// m2 = *p_m1;// MyClass m2(*p_m1);   //没问题   //调用了上面我们实现的拷贝构造函数delete (p_m1);*p_int = 888;for (auto i = 0; i < 10; i++){cout << m2.ptr[i] << endl;}std::cout << "Press ENTER to continue...";std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 读取内容直到用户输入enter键return EXIT_SUCCESS;
}

我用:

MyClass m2 = *p_m1;

能自动调用我们实现的拷贝构造函数,但是:

MyClass m2;
m2 = *p_m1;

却不行?

原因:

这是因为 MyClass m2 = *p_m1; 这种写法是定义并初始化一个新的对象
m2,在定义时就会调用拷贝构造函数来初始化它。而 MyClass m2; m2 = *p_m1; 这种写法是先定义了一个对象
m2,然后再将 *p_m1 赋值给它,这里的赋值操作会调用赋值运算符重载函数,而不是拷贝构造函数。 如果想要使用 m2 = *p_m1; 这种写法来调用拷贝构造函数,需要在类中实现赋值运算符重载函数。

另外一点需要注意:

MyClass m2 = *p_m1;

MyClass m2(*p_m1);

在用法上是等价的,可以理解为当我们调用MyClass m2 = *p_m1;时,相当于调用了MyClass m2(*p_m1);

如果我们想要使用MyClass m2; m2 = *p_m1;这种写法,只需要把等号=赋值运算符重载函数实现一下就好了:

MyClass &operator=(const MyClass &other)
{if (this->ptr != NULL){delete[] this->ptr;}this->ptr = new int[10];for (int i = 0; i < 10; i++){this->ptr[i] = other.ptr[i];}return *this;
}

但是同样,如果只实现了“等号=赋值运算符重载函数”,而“拷贝构造函数”未实现的话,那么 MyClass m2 = *p_m1;MyClass m2(*p_m1);的写法也都是不行了(默认浅拷贝)


http://www.ppmy.cn/news/59477.html

相关文章

Python--一言不合就try一下?

这里需要注意的是错误是Error&#xff0c;异常是Exception。 异常是可以被捕捉的&#xff0c;被处理的&#xff0c;但是错误是不能被捕获的。异常官方文档 ❝ 我们一般情况下&#xff0c;习惯性的叫pycharm控制台给出的红色字体叫报错。其实不然&#xff0c;是异常。 ❞ 异常产…

利用Python如何实现数据驱动的接口自动化测试

目录 前言 1、需求 2、方案 3、实现 总结 前言 大家在接口测试的过程中&#xff0c;很多时候会用到对CSV的读取操作&#xff0c;本文主要说明Python3对CSV的写入和读取。下面话不多说了&#xff0c;来一起看看详细的介绍吧。 1、需求 某API&#xff0c;GET方法&#xff…

Vulkan实战之Instance

文章目录 创建实例(**Creating an instance**)检查扩展支持(**Checking for extension support**)销毁清除(**Cleaning up**)最终代码 创建实例(Creating an instance) 您需要做的第一件事是通过创建一个实例来初始化Vulkan库。实例是应用程序和Vulkan库之间的连接&#xff0c…

Android9.0 原生系统SystemUI下拉状态栏和通知栏视图之锁屏通知布局

1.前言 在9.0的系统rom定制化开发中,对于系统原生systemui的锁屏界面的功能也是非常重要的,所以在锁屏页面布局中,也是有通知栏布局的,所以接下来对于息屏亮屏 通知栏布局的相关流程分析,看下亮屏后锁屏页面做了哪些功能 2.原生系统SystemUI下拉状态栏和通知栏视图之锁…

总结一下vue的关键字和用处

Vue.js 是一个轻量级的 JavaScript 框架&#xff0c;用于构建用户界面和单页面应用程序。下面是一些 Vue.js 中的关键字和它们的用途&#xff1a; v-bind&#xff1a;用于动态绑定属性和事件监听器。例如&#xff0c;可以用 v-bind 绑定一个元素的属性&#xff08;如&#xff…

node.js的核心模块

node的核心模块由一些精简而高效的库组成 文章目录 全局对象全局对象和全局变量processcosole utilutils.inheritsutils.inspect 事件机制事件发射器error 事件继承EventEmitter 文件系统访问fs.readFile(filename,[encoding],[callback(err,data)])fs.readFileSync(filename,…

Python小姿势 - ## Python中的迭代器与生成器

Python中的迭代器与生成器 在Python中&#xff0c;迭代是一个非常重要的概念&#xff0c;迭代器和生成器是迭代的两种最常见的形式。那么&#xff0c;迭代器与生成器有何不同呢&#xff1f; 首先&#xff0c;我们先来了解一下迭代器。 迭代器是一种对象&#xff0c;它可以记住遍…

Kubernetes云原生实战05 一键安装三主三从高可用集群

大家好,我是飘渺。 今天咱们继续更新Kubernetes云原生实战系列,本节文章会使用Kubekey安装一个三主三从的高可用集群。 在开始之前请分别登录kubernets集群节点,分别修改节点的主机名,跟第一章中提到的节点规划表保持一致。 hostnamectl set-hostname k8s-master1 hostn…