C++——类和对象(3)

目录

1. 拷贝构造

1.1 概念

1.2 特性

​编辑

2. 赋值重载 和 运算符重载

2.1 运算符重载

 2.2 赋值重载


此篇文章讲解六个默认成员函数中的  拷贝构造和赋值重载 


1. 拷贝构造

1.1 概念

拷贝构造:

  •                 在创建对象的时候用已经创建好的对象去初始化一个新对象;
  •                 只有一个形参,在用已存在的类类型对象创建新对象时由编译器自动调用。

1.2 特性

  • 拷贝构造是构造函数的一个重载形式;
  • 拷贝构造的参数只能有一个,且一般为类对象的常引用形式(常引用是因为不想传过来的对象被修改),不能传值,这样会引起无穷递归,编译器会直接报错;
class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}Date(const Date& d){_day = d._day;_month = d._month;_year = d._year;}void Print(){cout << "今天是" << _year << "年" << _month << "月" << _day << "日" << endl;}
private:int _year = 10;int _month = 10;int _day = 10;
};
  • 当对象采用传值调用的时候,不会把对象直接传过去,编译器会帮你调用类里面的拷贝构造;

  • 如果拷贝构造中的参数也是值而不是引用,则会发生无穷递归:

  •  若类中未显式定义拷贝构造,则编译器会自动生成一个拷贝构造,这个构造是值拷贝(浅拷贝),内置类型会帮你全部拷贝(按字节),自定义类型会帮你调用它的拷贝构造。
class Time
{
public:Time(const Time& t){_hour = t._hour;_min = t._min;_sec = t._sec;cout << "this is time structor!" << endl;}Time(int hour = 1, int min = 1, int sec = 1){_hour = hour;_min = min;_sec = sec;}
private:int _hour;int _min;int _sec;};class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}
private:int _year = 10;int _month = 10;int _day = 10;Time _t;
};int main()
{Date d1;Date d2(d1);
}

  • 编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了,还需要自己显式实现吗?当然像日期类这样的类是没必要的,如果像 Stack:
class Stack
{
public:Stack(int capacity){int* tmp = (int*)malloc(sizeof(int) * capacity);if (tmp == nullptr){perror("malloc error");exit(-1);}_arr = tmp;_size = 0;_capacity = capacity;}void Push(int x){//CheckCapacity()_arr[_size++] = x;}~Stack(){if (_arr != nullptr){free(_arr);_arr = nullptr;}_size = _capacity = 0;}private:int* _arr;int _size;int _capacity;
};int main()
{Stack st1(10);Stack st2(st1);}

 

  • st2 拷贝构造st1 ,这里是编译器默认生成的拷贝构造,默认是值拷贝,那么 不管是 int 类型的 size,capacity,还是指针类型的 arr 都会拷贝 st1 的,这样就会导致 st2 中的 _arr 和 st1 中的 _arr 指向同一块空间 ,在析构的时候 st2 会先 free() 那块 malloc 的空间,再析构 st1 的时候,free() 一块已释放的空间,那就会报错。

所以应该添加一份拷贝构造(深拷贝):

class Stack
{
public:Stack(int capacity){int* tmp = (int*)malloc(sizeof(int) * capacity);if (tmp == nullptr){perror("malloc error");exit(-1);}_arr = tmp;_size = 0;_capacity = capacity;}Stack(const Stack& st){_size = st._size;_capacity = st._capacity;int* tmp = (int*)malloc(sizeof(int) * _capacity);if (tmp == nullptr){perror("malloc error");exit(-1);}_arr = tmp;}void Push(int x){//CheckCapacity()_arr[_size++] = x;}~Stack(){if (_arr != nullptr){free(_arr);_arr = nullptr;}_size = _capacity = 0;}private:int* _arr;int _size;int _capacity;
};int main()
{Stack st1(10);Stack st2(st1);}

拷贝构造函数典型调用场景:

  • 使用已存在对象创建新对象
  • 函数参数类型为类类型对象
  • 函数返回值类型为类类型对象

 

  • 为了提高程序效率,一般对象传参时,尽量使用引用类型,返回时根据实际场景,能用引用尽量使用引用。

2. 赋值重载 和 运算符重载

2.1 运算符重载

 运算符重载:

  • C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
  • 函数名字为:关键字operator后面接需要重载的运算符符号。
  • 函数原型:返回值类型 operator操作符(参数列表)

注意:

  • 不能通过连接其他符号来创建新的操作符:比如operator@
  • 重载操作符必须有一个类类型参数
  • 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义
  • 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
  • .* :: sizeof ?: . 注意以上5个运算符不能重载。

例如:

class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}Date(const Date& d){_day = d._day;_month = d._month;_year = d._year;}bool operator==(const Date& d){return _year == d._year &&_month == d._month &&_day == d._day;}void Print(){cout << "今天是" << _year << "年" << _month << "月" << _day<< "日" << endl;}
private:int _year = 10;int _month = 10;int _day = 10;
};int main()
{Date d1(2024, 3, 17);Date d2(d1);bool ret1 = (d1 == d2);bool ret2 = (d1.operator==(d2));cout << ret1 << " " << ret2 << endl;
}

 2.2 赋值重载

1. 赋值运算符重载格式

  • 参数类型:const T&,传递引用可以提高传参效率
  • 返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
  • 检测是否自己给自己赋值
  • 返回 *this :要复合连续赋值的含义。
class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}Date(const Date& d){_day = d._day;_month = d._month;_year = d._year;}bool operator==(const Date& d){return _year == d._year &&_month == d._month &&_day == d._day;}Date& operator=(const Date& d){if (this != &d){_day = d._day;_year = d._year;_month = d._month;}return *this;}void Print(){cout << "今天是" << _year << "年" << _month << "月" << _day<< "日" << endl;}
private:int _year = 10;int _month = 10;int _day = 10;
};//int main()
//{
//	Date d1(2024, 3, 17);
//	Date d2(d1);
//	bool ret1 = (d1 == d2);
//	bool ret2 = (d1.operator==(d2));
//	cout << ret1 << " " << ret2 << endl;
//}int main()
{Date d1(2024, 3, 17);Date d2;d2.operator=(d1);d2.Print();d1.Print();bool ret1 = (d1 == d2);bool ret2 = (d1.operator==(d2));cout << ret1 << " " << ret2 << endl;
}
  • 赋值重载不能作为全局函数,只能重载成类的成员函数
// 错误示范
// 赋值运算符重载成全局函数,注意重载成全局函数时没有this指针了,需要给两个参数
Date& operator=(Date& left, const Date& right)
{if (&left != &right){left._year = right._year;left._month = right._month;left._day = right._day;}return left;
}

原因:如果不在类中定义赋值重载,那么编译器会自动生成一份,这是我们如果再类外声明             了一份,就会和类中默认的产生冲突,所以赋值重载只能是类的成员函数。

  • 用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类赋值运算符重载完成赋值。
  • 如果编译器能够自动生成那么还需要我们去编写赋值重载吗?这里其实和拷贝构造类似,如果不是动态开辟的空间,那么无所谓,但是如果成员变量有需要动态开辟的空间,那么就需要自己编写赋值重载,例如栈类:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/751546.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C# 打开文件对话框(OpenFileDialog)

OpenFileDialog&#xff1a;可以打开指定后缀名的文件&#xff0c;既能单个打开文件也能批量打开文件 /// <summary>/// 批量打开文档/// 引用&#xff1a;System.Window.Fomrs.OpenFileDialog/// </summary>public void OpenFile(){OpenFileDialog dialog new Op…

操作系统(OS)

文章目录 前言一、操作系统是什么&#xff1f;二、用户对资源的访问三、操作系统是怎么做到管理的&#xff1f; 前言 任何计算机系统都包含一个基本的程序集合&#xff0c;称为操作系统(OS)。冯诺依曼体系结构中的硬件单元提供的功能&#xff0c;这些硬件由操作系统来控制与管…

整数和浮点数在内存中存储及题目

一、整数在内存中存储 整数的2进制表⽰⽅法有三种&#xff0c;即原码、反码和补码。三种表⽰⽅法均有符号位和数值位两部分&#xff0c;符号位都是⽤0表⽰“正”&#xff0c;⽤1表⽰“负”&#xff0c;⽽数值位最⾼位的⼀位是被当做符号位&#xff0c;剩余的都是数值位 正整数…

UglifyJS 压缩工具

要使用 UglifyJS 进行 JavaScript 代码的压缩和混淆&#xff0c;你可以按照以下步骤进行&#xff1a; 安装 Node.js&#xff1a; 首先确保你的计算机上安装了 Node.js。如果没有安装&#xff0c;你可以从 Node.js 官方网站 下载并安装。 安装 UglifyJS&#xff1a; 在安装 Nod…

2024腾讯云免费服务器2核8G配置申请流程,亲测有效

腾讯云免费服务器申请入口 https://curl.qcloud.com/FJhqoVDP 免费服务器可选轻量应用服务器和云服务器CVM&#xff0c;轻量配置可选2核2G3M、2核8G7M和4核8G12M&#xff0c;CVM云服务器可选2核2G3M和2核4G3M配置&#xff0c;腾讯云服务器网txyfwq.com分享2024年最新腾讯云免费…

C++for语句(2)

11.乘方计算 给出一个整数a和一个正整数n&#xff08;-1000000<a<1000000,1<n<100000&#xff09;&#xff0c;求乘方&#xff0c;即乘方的结果。最终结果的绝对值不超过1000000。 输入 一行&#xff0c;包含两个整数a和n&#xff08;-1000000<a<1000000,1…

第四十四周:文献阅读 + SG滤波+基于LSTM的编码器-解码器

目录 摘要 Abstract 文献阅读&#xff1a;基于集成深度神经网络的大规模水质预测 现有问题 提出方法 方法论 Savitsky-Golay过滤器 SE-LSTM&#xff08;基于LSTM的编码器-解码器神经网络&#xff09; 研究实验 数据集 实验设置 评估指标 基准模型 实验结果 发展…

搜维尔科技:使用SenseGlove Nova手套操纵其“CAVE”投影室中的虚拟对象

创造了一种基于 PC 的创新型多边沉浸式环境&#xff0c;让参与者完全被虚拟图像和声音包围。 需要解决的挑战&#xff1a; 传统的 VR 系统往往缺乏真实的触摸反馈&#xff0c;限制了用户的沉浸感。AVR Japan 旨在通过将触觉技术融入到他们的 CAVE 系统中来应对这一挑战&#x…

操作系统(AndroidIOS)图像绘图的基本原理

屏幕显示图像的过程 我们知道&#xff0c;屏幕是由一个个物理显示单元组成&#xff0c;每一个单元我们可以称之为一个物理像素点&#xff0c;而每一个像素点可以发出多种颜色。 而图像&#xff0c;就是在不同的物理像素点上显示不同的颜色构成的。 像素点的颜色 像素的颜色是…

HTML静态网页成品作业(HTML+CSS)——游戏战地介绍设计制作(4个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有4个页面。 二、作品演示 三、代…

3.4 bp,si,di寄存器,寻址方式,寄存器总结

汇编语言 1. [bxidata] 我们可以用[bx]来指明一个内存单元我们也可以用[bxidata]来表示一个内存单元&#xff0c;它的偏移地址为bx中的数值加上idata mount c d:masm c: debug r d 2000:1000 e 2000:1000 12 34 56 78 a mov ax,2000 mov ds,ax mov bx,1000 mov ax,[bx] mov c…

C++之deque与vector、list对比分析

一.deque讲解 对于vector和list&#xff0c;前一个是顺序表&#xff0c;后一个是带头双向循环链表&#xff0c;前面我们已经实现过&#xff0c;这里就不再讲解了&#xff0c;直接上deque了。 deque&#xff1a;双端队列 常见接口大家可以查看下面链接&#xff1a; deque - …

Redis - String 字符串

前言 下表中包含本博客提到的所有命令 字符串类型是 Redis 最基础的数据类型&#xff0c;关于字符串需要特别注意&#xff1a; 1&#xff09;⾸先 Redis 中所有的键&#xff08;key&#xff09;的类型都是字符串类型&#xff0c;⽽且其他⼏种数据结构也都是在字符串类似基础上…

Figure 01掀起了具身智能的崭新篇章

在人工智能的发展历程中&#xff0c;OpenAI始终扮演着创新的先锋角色。最近&#xff0c;他们与Figure公司的合作成果尤为引人注目&#xff0c;这一合作将多模态大模型技术成功应用于Figure 01机器人的开发中&#xff0c;为人类与机器的互动开辟了全新的时代。该机器人不仅能够与…

Matlab|【免费】基于半不变量的概率潮流计算

目录 主要内容 部分代码 结果一览 下载链接 主要内容 该程序主要内容是基于半不变量法的概率潮流&#xff0c;包含蒙特卡洛模拟法、半不变量法&#xff0b;Gram-Charlier级数展开以及半不变量法Cornish-Fisher级数展开三种方法以及效果对比&#xff0c;模型考虑了…

Python 查找并高亮PDF中的指定文本

在处理大量PDF文档时&#xff0c;有时我们需要快速找到特定的文本信息。本文将提供以下三个Python示例来帮助你在PDF文件中快速查找并高亮指定的文本。 查找并高亮PDF中所有的指定文本查找并高亮PDF某个区域内的指定文本使用正则表达式搜索指定文本并高亮 本文将用到国产第三方…

cesium.js加载模型后,重新设置旋转角度属性值

// 加载模型var position Cesium.Cartesian3.fromDegrees(longitude, latitude, height);// 计算矩阵var rollAngleDegrees 15; // 设置翻滚角度var rollAngleRadians Cesium.Math.toRadians(rollAngleDegrees); // 将角度转换为弧度var orientation Cesium.Transforms.eas…

安装Pytorch——CPU版本

安装Pytorch——CPU版本 1. 打开pytorch官网2. 选择pip安装pytorch-cpu3.复制安装命令4. 在cmd命令窗口&#xff0c;进入你的虚拟环境4.1 创建虚拟环境4.2 进行安装 5. 安装成功6. 进行测试——如下面步骤&#xff0c;如图6.1 输入 python6.2 输入 import torch6.2 输入 print …

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:Web)中篇

onBeforeUnload onBeforeUnload(callback: (event?: { url: string; message: string; result: JsResult }) > boolean) 刷新或关闭场景下&#xff0c;在即将离开当前页面时触发此回调。刷新或关闭当前页面应先通过点击等方式获取焦点&#xff0c;才会触发此回调。 参数…

微信小程序-微信支付

微信支付介绍 梳理一下流程&#xff1a; 1、用户点击下单&#xff0c;小程序向商户系统&#xff08;我们的服务器&#xff09;发起请求&#xff0c;服务器生成一个唯一订单号给小程序。 2、小程序向服务器发起微信支付请求&#xff0c;服务器调用微信下单接口&#xff0c;微信…