【C++】运算符重载案例 - 字符串类 ② ( 重载 等号 = 运算符 | 重载 数组下标 [] 操作符 | 完整代码示例 )
文章目录
- 一、重载 等号 = 运算符
- 1、等号 = 运算符 与 拷贝构造函数
- 2、重载 等号 = 运算符 - 右操作数为 String 对象
- 3、不同的右操作数对应的 重载运算符函数
- 二、重载 下标 [] 运算符
- 三、完整代码示例
- 1、String.h 类头文件
- 2、String.cpp 类实现
- 3、Test.cpp 测试类
- 4、执行结果
一、重载 等号 = 运算符
1、等号 = 运算符 与 拷贝构造函数
等号 = 操作符 的 作用是 使用一个现有对象 为 另外一个现有对象赋值 ;
- 注意与 拷贝构造函数 区分 , 拷贝构造函数是 使用一个先有对象 为 一个新的对象进行初始化 ;
- 下面的代码中 , 分别调用 等号操作符 和 拷贝构造函数 ;
String s1, s2;
s1 = s2; // 这是使用 等号操作符 进行运算
String s3 = s2; // 这是使用 拷贝构造函数
2、重载 等号 = 运算符 - 右操作数为 String 对象
使用 成员函数 实现 重载 等号 = 运算符 :
- 首先 , 写出函数名 , 函数名规则为 " operate " 后面跟上要重载的运算符 ,
- 2 2 2 个对象
Student s1, s2之间进行 等号运算 , 使用一个现有对象 为 另外一个现有对象赋值 ; - 使用时用法为
s1 = s2; - 函数名是
operator=;
- 2 2 2 个对象
operator=
- 然后 , 根据操作数 写出函数参数 , 参数一般都是 对象的引用 ;
- 等号运算符 使用时用法为
s1 = s2; - 左操作数 : 其中 左操作数 是 s1 , 这里通过 this 指针调用 , 不需要声明在参数中 ;
- 右操作数 - 情况 ① : 右操作数 也是 String 对象 ; 该操作数需要声明在参数中 , 注意 普通数据类型 直接声明 , 对象数据类型 需要声明 为 引用类型 ;
- 上述两个是对象类型 , 对象一般传入 指针 或 引用 , 由于是基础数据类型 , 这里传入基础数据类型 ; 如果是 对象类型 , 则传入引用 ;
- 右操作数 - 情况 ② : 还有一种情况是
s1 = "Tom"的用法 , 这样 右操作数 是 char* 类型的字符串 ;
- 等号运算符 使用时用法为
operator=(const String& s) // 传入 String 对象 , 使用 const 修饰参数 , 防止传入的对象被修改
operator=(const char* p) // 传入字符串值
- 再后 , 根据业务完善返回值 , 返回值可以是 引用 / 指针 / 元素 ;
- 此处返回值返回 String& 对象引用 , 可用于其它链式调用 ;
- 如果返回 String 对象 , 则是一次性的匿名对象 ;
String& operator=(const String& s) // 传入 String 对象 , 使用 const 修饰参数 , 防止传入的对象被修改
String& operator=(const char* p) // 传入字符串值
- 最后 , 实现函数体 , 编写具体的运算符操作业务逻辑 ;
- 先把本对象已分配的内存释放掉 ;
- 再进行赋值操作 ;
3、不同的右操作数对应的 重载运算符函数
不同的右操作数对应的 重载运算符函数 :
- 右操作数是 String 对象的情况 :
// 重载等号 = 操作符 , 右操作数是 String 对象的情况
String& String::operator=(const String& s)
{// 先处理本对象已分配的内存if (this->m_p != NULL){// 之前使用 new 分配的内存// 释放内存就需要使用 delete // 使用 malloc 分配的内存需要使用 free 释放delete[] this->m_p;// 设置指针指为空 , 避免出现野指针this->m_p = NULL;// 设置字符串长度为 0this->m_len = 0;}// 拷贝字符串长度// 注意 : 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'this->m_len = s.m_len;// 使用 new 关键字为 char* m_p; 指针分配内存// 对于基础数据类型 new 等同于 mallocthis->m_p = new char[this->m_len + 1];// 拷贝字符串到 m_p 指向的内存中strcpy(this->m_p, s.m_p);cout << "调用重载等号 = 操作符函数 String& String::operator=(const String& s)" << endl;return *this;
}
- 右操作数为 字符串指针 的情况 :
// 重载等号 = 操作符 , 右操作数是 字符串常量值 的情况
String& String::operator=(const char* p)
{// 先处理本对象已分配的内存if (this->m_p != NULL){// 之前使用 new 分配的内存// 释放内存就需要使用 delete // 使用 malloc 分配的内存需要使用 free 释放delete[] this->m_p;// 设置指针指为空 , 避免出现野指针this->m_p = NULL;// 设置字符串长度为 0this->m_len = 0;}// 拷贝字符串长度// 注意 : 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'this->m_len = strlen(p);// 使用 new 关键字为 char* m_p; 指针分配内存// 对于基础数据类型 new 等同于 mallocthis->m_p = new char[this->m_len + 1];// 拷贝字符串到 m_p 指向的内存中strcpy(this->m_p, p);cout << "调用重载等号 = 操作符函数 String& String::operator=(const char* p)" << endl;return *this;
}
二、重载 下标 [] 运算符
使用 成员函数 实现 重载 下标 [] 运算符 :
- 首先 , 写出函数名 , 函数名规则为 " operate " 后面跟上要重载的运算符 ,
- 下标 [] 运算符 , 使用时用法为
s[10]; - 重载 下标 [] 运算符 函数名是
operator[];
- 下标 [] 运算符 , 使用时用法为
operator[]
- 然后 , 根据操作数 写出函数参数 , 参数一般都是 对象的引用 ;
- 下标 运算符 使用时用法为
s[10]; - 左操作数 : 其中 左操作数 是 s 对象 , 这里通过 this 指针调用 , 不需要声明在参数中 ;
- 右操作数 : 右操作数 是 int 类型 索引值 ;
- 下标 运算符 使用时用法为
operator[](int i)
- 再后 , 根据业务完善返回值 , 返回值可以是 引用 / 指针 / 元素 ;
- 此处返回值 是 char 类型的 , 返回具体字符串指定索引的 char 类型字符 ;
- char 字符是内存中的一个地址中的值 , 这里返回引用类型 ;
char& operator[](int i)
- 最后 , 实现函数体 , 编写具体的运算符操作业务逻辑 ;
// 重载 数组下标 [] 操作符
char& String::operator[](int i)
{// 直接返回对应 i 索引字符return this->m_p[i];
}
三、完整代码示例
1、String.h 类头文件
#pragma once#include "iostream"
using namespace std;class String
{
public:// 默认的无参构造函数String();// 有参构造函数 , 接收一个 char* 类型字符串指针String(const char* p);// 拷贝构造函数 , 使用 String 对象初始化 对象值String(const String& s);// 析构函数~String();public:// 重载等号 = 操作符 , 右操作数是 String 对象的情况String& operator=(const String& s);// 重载等号 = 操作符 , 右操作数是 字符串常量值 的情况String& operator=(const char* p);// 重载 数组下标 [] 操作符char& operator[](int i);private:// 字符串长度 , 不包括 '\0'// 内存占用空间大小 = 字符串长度 + 1int m_len;// 字符串指针, 指向堆内存中的字符串char* m_p;
};
2、String.cpp 类实现
// 使用 strcpy 函数报错
// error C4996: 'strcpy': This function or variable may be unsafe.
// Consider using strcpy_s instead.
// To disable deprecation, use _CRT_SECURE_NO_WARNINGS.
// See online help for details.
#define _CRT_SECURE_NO_WARNINGS#include "String.h"// 默认的无参构造函数
String::String()
{// 默认构造一个空字符串 , 字符串长度为 0 // 但是 , 字符串指针 指向的内存空间大小是 1 , 内容是 '\0'm_len = 0;// 使用 new 关键字为 char* m_p; 指针分配内存// 对于基础数据类型 new 等同于 mallocm_p = new char[m_len + 1];// 拷贝空字符串到 m_p 指向的内存中strcpy(m_p, "");cout << "调用无参构造函数" << endl;
}// 有参构造函数 , 接收一个 char* 类型字符串指针
String::String(const char* p)
{if (p == NULL){// 默认构造一个空字符串 , 字符串长度为 0 // 但是 , 字符串指针 指向的内存空间大小是 1 , 内容是 '\0'this->m_len = 0;// 使用 new 关键字为 char* m_p; 指针分配内存// 对于基础数据类型 new 等同于 mallocthis->m_p = new char[this->m_len + 1];// 拷贝空字符串到 m_p 指向的内存中strcpy(m_p, "");}else{// 获取传入字符串的长度// 但是 , 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'this->m_len = strlen(p);// 使用 new 关键字为 char* m_p; 指针分配内存// 对于基础数据类型 new 等同于 mallocthis->m_p = new char[this->m_len + 1];// 拷贝字符串到 m_p 指向的内存中strcpy(m_p, p);}cout << "调用有参构造函数" << endl;
};// 拷贝构造函数 , 使用 String 对象初始化 对象值
String::String(const String& s)
{// 拷贝字符串长度// 注意 : 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'this->m_len = s.m_len;// 使用 new 关键字为 char* m_p; 指针分配内存// 对于基础数据类型 new 等同于 mallocthis->m_p = new char[this->m_len + 1];// 拷贝字符串到 m_p 指向的内存中strcpy(this->m_p, s.m_p);cout << "调用拷贝构造函数" << endl;
}// 析构函数
String::~String()
{if (this->m_p != NULL){// 之前使用 new 分配的内存// 释放内存就需要使用 delete // 使用 malloc 分配的内存需要使用 free 释放delete[] this->m_p;// 设置指针指为空 , 避免出现野指针this->m_p = NULL;// 设置字符串长度为 0this->m_len = 0;}
}// 重载等号 = 操作符 , 右操作数是 String 对象的情况
String& String::operator=(const String& s)
{// 先处理本对象已分配的内存if (this->m_p != NULL){// 之前使用 new 分配的内存// 释放内存就需要使用 delete // 使用 malloc 分配的内存需要使用 free 释放delete[] this->m_p;// 设置指针指为空 , 避免出现野指针this->m_p = NULL;// 设置字符串长度为 0this->m_len = 0;}// 拷贝字符串长度// 注意 : 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'this->m_len = s.m_len;// 使用 new 关键字为 char* m_p; 指针分配内存// 对于基础数据类型 new 等同于 mallocthis->m_p = new char[this->m_len + 1];// 拷贝字符串到 m_p 指向的内存中strcpy(this->m_p, s.m_p);cout << "调用重载 等号 = 操作符函数 String& String::operator=(const String& s)" << endl;return *this;
}// 重载等号 = 操作符 , 右操作数是 字符串常量值 的情况
String& String::operator=(const char* p)
{// 先处理本对象已分配的内存if (this->m_p != NULL){// 之前使用 new 分配的内存// 释放内存就需要使用 delete // 使用 malloc 分配的内存需要使用 free 释放delete[] this->m_p;// 设置指针指为空 , 避免出现野指针this->m_p = NULL;// 设置字符串长度为 0this->m_len = 0;}// 拷贝字符串长度// 注意 : 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'this->m_len = strlen(p);// 使用 new 关键字为 char* m_p; 指针分配内存// 对于基础数据类型 new 等同于 mallocthis->m_p = new char[this->m_len + 1];// 拷贝字符串到 m_p 指向的内存中strcpy(this->m_p, p);cout << "调用重载 等号 = 操作符函数 String& String::operator=(const char* p)" << endl;return *this;
}// 重载 数组下标 [] 操作符
char& String::operator[](int i)
{cout << "调用重载 下标 [] 操作符函数 char& String::operator[](int i)" << endl;// 直接返回对应 i 索引字符return this->m_p[i];
}
3、Test.cpp 测试类
#include "iostream"
using namespace std;// 导入自定义的 String 类
#include "String.h"int main() {// 调用无参构造函数String s1;// 调用有参构造函数String s2("Tom");// 调用拷贝构造函数String s3 = s2;// 调用重载的等号运算符函数, 右操作数是 String 对象s1 = s2;// 调用重载的等号运算符函数, 右操作数是 字符串常量值 , char* 指针类型s3 = "Jerry";// 调用重载的下标运算符函数char c = s3[3];// 控制台暂停 , 按任意键继续向后执行system("pause");return 0;
}
4、执行结果
执行结果 :
调用无参构造函数
调用有参构造函数
调用拷贝构造函数
调用重载 等号 = 操作符函数 String& String::operator=(const String& s)
调用重载 等号 = 操作符函数 String& String::operator=(const char* p)
调用重载 下标 [] 操作符函数 char& String::operator[](int i)

相关文章:
【C++】运算符重载案例 - 字符串类 ② ( 重载 等号 = 运算符 | 重载 数组下标 [] 操作符 | 完整代码示例 )
文章目录 一、重载 等号 运算符1、等号 运算符 与 拷贝构造函数2、重载 等号 运算符 - 右操作数为 String 对象3、不同的右操作数对应的 重载运算符函数 二、重载 下标 [] 运算符三、完整代码示例1、String.h 类头文件2、String.cpp 类实现3、Test.cpp 测试类4、执行结果 一…...
Vue脚手架开发流程
一、项目运行时会先执行 public / index.html 文件 <!DOCTYPE html> <html lang""><head><meta charset"utf-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport&quo…...
从零开始学习线性回归:理论、实践与PyTorch实现
文章目录 🥦介绍🥦基本知识🥦代码实现🥦完整代码🥦总结 🥦介绍 线性回归是统计学和机器学习中最简单而强大的算法之一,用于建模和预测连续性数值输出与输入特征之间的关系。本博客将深入探讨线性…...
[LeetCode]链式二叉树相关题目(c语言实现)
文章目录 LeetCode965. 单值二叉树LeetCode100. 相同的树LeetCode101. 对称二叉树LeetCode144. 二叉树的前序遍历LeetCode94. 二叉树的中序遍历LeetCode145. 二叉树的后序遍历LeetCode572. 另一棵树的子树 LeetCode965. 单值二叉树 题目 Oj链接 思路 一棵树的所有值都是一个…...
集成学习
集成学习(Ensemble Learning) - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/27689464集成学习就是组合这里的多个弱监督模型以期得到一个更好更全面的强监督模型,集成学习潜在的思想是即便某一个弱分类器得到了错误的预测,其他的弱分类器…...
算法练习11——买卖股票的最佳时机 II
LeetCode 122 买卖股票的最佳时机 II 给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。 在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。 返回…...
linux——多线程,线程控制
目录 一.POSIX线程库 二.线程创建 1.创建线程接口 2.查看线程 3.多线程的健壮性问题 4.线程函数参数传递 5.线程id和地址空间 三.线程终止 1.pthread_exit 2.pthread_cancel 四.线程等待 五.线程分离 一.POSIX线程库 站在内核的角度,OS只有轻量级进程…...
Oracle 简介与 Docker Compose部署
最近,我翻阅了在之前公司工作时的笔记,偶然发现了一些有关数据库的记录。当初,我们的项目一开始采用的是 Oracle 数据库,但随着项目需求的变化,我们不得不转向使用 SQL Server。值得一提的是,公司之前采用的…...
mp4音视频分离技术
文章目录 问题描述一、分离MP3二、分离无声音的MP4三、结果 问题描述 MP4视频想拆分成一个MP3音频和一个无声音的MP4文件 一、分离MP3 ffmpeg -i C:\Users\Administrator\Desktop\一个文件夹\我在财神殿里长跪不起_完整版MV.mp4 -vn C:\Users\Administrator\Desktop\一个文件…...
JVM 参数
JVM 参数类型大致分为以下几类: 标准参数(-):保证在所有的 JVM 实现都支持的参数非标准参数(-X):通用的,特定于 HotSpot 虚拟机的参数,这些参数不保证在所有 JVM 实现中…...
黑马点评-07缓存击穿问题(热点key失效)及解决方案,互斥锁和设置逻辑过期时间
缓存击穿问题(热点key失效) 缓存击穿问题也叫热点Key问题,就是一个被高并发访问并且重建缓存业务较复杂的key突然失效了,此时无数的请求访问会在瞬间打到数据库,带来巨大的冲击 一件秒杀中的商品的key突然失效了,由于大家都在疯狂抢购那么这个瞬间就会有无数的请求…...
信息系统项目管理师第四版学习笔记——项目进度管理
项目进度管理过程 项目进度管理过程包括:规划进度管理、定义活动、排列活动顺序、估算活动持续时间、制订进度计划、控制进度。 规划进度管理 规划进度管理是为规划、编制、管理、执行和控制项目进度而制定政策、程序和文档的过程。本过程的主要作用是为如何在…...
指挥棒:C++ 与运算符
文章目录 参考描述算术运算符除法运算取模运算复合赋值运算符自增运算符自减运算符 比较运算符逻辑运算符概念短路为什么需要短路机制? 参考 项目描述微软C 语言文档搜索引擎Bing、GoogleAI 大模型文心一言、通义千问、讯飞星火认知大模型、ChatGPTC Primer Plus &…...
HTTPS建立连接的过程
HTTPS 协议是基于 TCP 协议的,因而要先建立 TCP 的连接。在这个例子中,TCP 的连接是在手机上的 App 和负载均衡器 SLB 之间的。 尽管中间要经过很多的路由器和交换机,但是 TCP 的连接是端到端的。TCP 这一层和更上层的 HTTPS 无法看到中间的包…...
Python接口自动化搭建过程,含request请求封装!
开篇碎碎念 接口测试自动化好处 显而易见的好处就是解放双手😀。 可以在短时间内自动执行大量的测试用例通过参数化和数据驱动的方式进行测试数据的变化,提高测试覆盖范围快速反馈测试执行结果和报告支持持续集成和持续交付的流程 使用Requestspytes…...
Vue3 编译原理
文章目录 一、编译流程1. 解读入口文件 packgages/vue/index.ts2. compile函数的运行流程 二、AST 解析器1. ast 的生成2. 创建ast的根节点3. 解析子节点 parseChildren(关键)4. 解析模版元素 Element模版元素解析-举例分析 一、编译流程 1. 解读入口文…...
spring boot整合Minio
MinIO 安装MinIo # 先创建minio 文件存放的位置 mkdir -p /opt/docker/minio/data# 启动并指定端口 docker run \-p 9000:9000 \-p 5001:5001 \--name minio \-v /opt/docker/minio/data:/data \-e "MINIO_ROOT_USERminioadmin" \-e "MINIO_ROOT_PASSWORDmini…...
Hadoop----Azkaban的使用与一些报错问题的解决
1.因为官方只放出源码,并没有放出其tar包,所以需要我们自己编译,通过查阅资料我们可以使用gradlew对其进行编译,还是比较简单,然后将里面需要用到的服务文件夹进行拷贝,完善其文件夹结构,通常会…...
「新房家装经验」客厅电视高度标准尺寸及客厅电视机买多大尺寸合适?
客厅电视悬挂高度标准尺寸是多少? 客厅电视悬挂高度通常在90~120厘米之间,电视挂墙高度也可以根据个人的喜好和实际情况来调整,但通常不宜过高,以坐在沙发上观看时眼睛能够平视到电视中心点或者中心稍微往下一点的位置为适宜。 客…...
ArduPilot开源飞控之AP_Baro_DroneCAN
ArduPilot开源飞控之AP_Baro_DroneCAN 1. 源由2. back-end抽象类3. 方法实现3.1 probe3.2 update3.3 subscribe_msgs3.4 handle_pressure/handle_temperature3.5 CAN port 4. 参考资料 1. 源由 鉴于ArduPilot开源飞控之AP_Baro中涉及Sensor Driver有以下总线类型: …...
XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...
关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
Python Einops库:深度学习中的张量操作革命
Einops(爱因斯坦操作库)就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库,用类似自然语言的表达式替代了晦涩的API调用,彻底改变了深度学习工程…...
day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...
