【C++】string类模拟实现过程中值得注意的点
👀樊梓慕:个人主页
🎥个人专栏:《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C++》《Linux》
🌝每一个不曾起舞的日子,都是对生命的辜负
目录
前言
1.有关const的使用
(1)const修饰形参
(2)const修饰返回值
(3)const修饰成员函数
2.有关声明与定义分离可能出现的问题
(1)合并命名空间
(2) 指定类域
(3)当声明与定义分离时,缺省参数只需要在声明中体现
(4)函数重定义问题
3.有关模拟实现的传统写法与现代写法
4.有关string类流插入和流提取操作符的实现思维定势陷阱
前言
本篇文章旨在记录博主在模拟实现string类中遇到的一些问题,希望与大家共勉,在模拟实现string类的过程中运用了之前所学的很多知识,包括一些问题的出现都是对之前所学知识的考验,为了更加深入的了解和掌握string类,大家不妨跟随博主的步伐一起,看看遇到这些问题时,你是否可以轻松应对,利用之前所学解决实际问题。
欢迎大家📂收藏📂以便未来做题时可以快速找到思路,巧妙的方法可以事半功倍。
=========================================================================
GITEE相关代码:🌟fanfei_c的仓库🌟
=========================================================================
1.有关const的使用
(1)const修饰形参
首先我们来看string类中这些函数的模拟实现:
//relational operators
bool operator>(const string& s);
bool operator==(const string& s);
bool operator<=(const string& s);
bool operator<(const string& s);
bool operator>=(const string& s);
bool operator!=(const string& s);
为什么用const修饰形参?
- const修饰形参的意义主要体现在输入型参数上,尤其是指针类型和引用,const修饰某个变量,肯定是为了保护该变量的值不被改变。
那什么时候我们需要保护这个值不会被改变呢?
- 当然是我们需要他作为函数的输入时,输出型参数我们需要他根据函数功能做出改变,所以肯定不需要用const修饰。
那我为什么又说const修饰输入型参数尤其在指针类型和引用呢?其他普通类型呢?
- 因为我们知道形参是实参的一份临时拷贝,形参的改变不会影响实参,所以我们也就不需要保护它,因为它的改变不会影响到实参本身。
那为什么要用引用,我直接传不就得了,反正也只是拷贝,不会影响本身,这样也省得使用const来保护了。
- 这里传递引用的价值就在于可以极大的优化节省调用函数的代价!
我们知道引用就是本身的一个别名,实际上就是本身,所以当我们传递引用时,就节省了拷贝的代价,为了效率我们值得做出这样的操作,但为了保护好我们本身不被修改,一定要用const修饰,这样可以增强程序的健壮性!防止我们的程序崩溃。
(2)const修饰返回值
同样我们用模拟实现来引入。
//access
char& operator[](size_t index);
const char& operator[](size_t index)const;
这里为什么要实现两个版本的下标访问?
类的有些对象可能可以改变,有的不能改变,举个例子来说,对于string对象来说,有的我们可能希望定义的string对象可以改变,有的则不能改变:
string str1= "hello world";
const string str2 = "hello world";
我们如果进行下标操作符运算,str1[0]='f'这是允许的,而str2[1]='f'则是不允许的。
并且这两个操作调用的成员函数也是不一样的,前一个调用的是string类的非const成员函数,后一个调用的是string类的const成员函数
如果我们没有定义const成员函数,则str2会调用相应的非const成员函数,从而导致我们本来不想其被修改的对象被意外修改。
const修饰返回值的意义何在?
实际上,如果函数返回的是普通的变量,即值传递,那确实没有什么意义,因为根据前面的学习,函数是如何返回值的呢,实际上是拷贝,拷贝一份内容相同的常量返回,那它本来就是常量你再用const修饰那不多此一举了么。
是的,所以如果函数返回采用值传递的方式,那const这里就没有任何意义。
const修饰返回值真正的意义在于指针传递返回,用来赋值给const修饰的指针内容。
例如函数:
const char* string::c_str()const
{return _str;
}
接收这个函数的返回值我们需要:
void test5()
{string s1 = "hello world!!!!!!!!!!!!!!!!";const char* tmp=s1.c_str();cout << tmp << endl;
}
为什么要使用引用做返回值?
首先明确:
- 之前我们说过,除了函数作用域,返回对象就会被销毁,不能用引用返回,否则结果是不确定的。
那这里为什么可以这样使用呢?
- 是因为string所使用的空间为动态内存new来的,我们说引用做返回值,可用静态变量或动态内存。
引用做返回值的主要目的就是能够修改返回的内容,加const是为了适配const string str="abc"这种被const修饰了的字符串。
(3)const修饰成员函数
同样我们用string类的模拟实现引入:
// 返回c在string中第一次出现的位置
size_t find(char c, size_t pos = 0) const;
// 返回子串s在string中第一次出现的位置
size_t find(const char* s, size_t pos = 0) const;
const修饰成员函数实际上修饰的是该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。
任何不会修改数据成员的函数都应该声明为const 类型(这样const对象和非const对象都可以调用该函数)。如果在编写const 成员函数时,不慎修改了数据成员,或者调用了其它非const 成员函数,编译器将指出错误,这无疑会提高程序的健壮性。
即,
- const对象不可以调用非const成员函数;
- 非const对象可以调用const成员函数;
- const成员函数内部不能调用其他非const成员函数;
- 非const成员函数内部可以调用其他const成员函数。
总结为:权限可以缩小,但是权限不可以放大!
2.有关声明与定义分离可能出现的问题
博主在实现string类时,统一的把函数定义都以内联的形式实现了,当然后期实现完成尝试着想要声明与定义分离下,但却出现了很多报错,这里我梳理一下,形成了以下内容。
(1)合并命名空间
首先分离后的第一个问题就是,由于我之前在头文件中类的实现部分都包含在了命名空间内部。
即,
所以首先需要解决这一问题,我们可以采用左图这种方式,当然右面的方式显然更好:
(2) 指定类域
由于声明定义分离,所以我们需要指定类域:
(3)当声明与定义分离时,缺省参数只需要在声明中体现
(4)函数重定义问题
如果.h文件中存在函数定义(不包括成员函数),只要存在多个cpp文件,并且他们都包含了string.h头文件,那他们在展开时就会出现重定义的问题。
3.有关模拟实现的传统写法与现代写法
我们来观察一下两种实现方式的区别:
//传统写法
string::string(const string& s)
{_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;
}
//现代写法
string::string(const string& s)
{string tmp(s._str);swap(tmp);
}
//结合swap来观察
void string::swap(string& s)
{std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);
}
那现代写法优越在哪呢?
现代写法非常巧妙,他完全利用了我们学习构造函数部分的知识。
首先完成用s._str完成构造tmp对象,然后交换*this与tmp,交换后tmp析构。
4.有关string类流插入和流提取操作符的实现思维定势陷阱
在之前的学习中,我们知道流插入与流提取的实现要放在全局从而保证第一个参数不为this指针,但当时面临一个问题,我们实现的是日期类,想要打印日期类就必须访问到类的成员变量,但我们知道成员变量一般都是私有的,所以我们引入了友元的概念用来解决这一问题。
=========================🐸这部分忘了的老铁可以戳🐸=========================
樊梓慕---类和对象(中)之拷贝构造与运算符、操作符重载【CSDN】http://t.csdnimg.cn/2wbiI🐸🐸🐸🐸🐸🐸🐸🐸🐸🐸🐸🐸🐸🐸🐸🐸🐸🐸🐸🐸🐸🐸🐸🐸🐸🐸🐸🐸🐸🐸🐸
但这里我们需不需要利用友元呢?
ostream& operator<<(ostream& _cout, const F::string& s)
{for (auto e : s){_cout << e;}return _cout;
}
istream& operator>>(istream& _cin, F::string& s)
{s.clear();char buff[128];char ch = _cin.get();int i = 0;while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == 127){buff[i] = '\0';s += buff;i = 0;}ch = _cin.get();}if (i > 0){buff[i] = '\0';s += buff;}return _cin;
}
我们并没有访问string类的成员变量,所以这里不需要利用友元!
🚨请不要形成思维定势,要活学活用🚨
=========================================================================
如果你对该系列文章有兴趣的话,欢迎持续关注博主动态,博主会持续输出优质内容
🍎博主很需要大家的支持,你的支持是我创作的不竭动力🍎
🌟~ 点赞收藏+关注 ~🌟
=========================================================================
相关文章:

【C++】string类模拟实现过程中值得注意的点
👀樊梓慕:个人主页 🎥个人专栏:《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》 🌝每一个不曾起舞的日子,都是对生命的辜负 目录 前言 1.有关const的使用 &#x…...

大数据湖项目建设方案:文档全文101页,附下载
关键词:大数据解决方案,数据湖解决方案,数据治理解决方案,数据中台解决方案 一、大数据湖建设思路 1、明确目标和定位:明确大数据湖的目标和定位是整个项目的基础,这可以帮助我们确定项目的内容、规模、所…...

通付盾Web3专题 | SharkTeam:起底朝鲜APT组织Lazarus Group,攻击手法及洗钱模式
国家级APT(Advanced Persistent Threat,高级持续性威胁)组织是有国家背景支持的顶尖黑客团伙,专门针对特定目标进行长期的持续性网络攻击。朝鲜APT组织Lazarus Group就是非常活跃的一个APT团伙,其攻击目的主要以窃取资…...

<蓝桥杯软件赛>零基础备赛20周--第8周第1讲--十大排序
报名明年4月蓝桥杯软件赛的同学们,如果你是大一零基础,目前懵懂中,不知该怎么办,可以看看本博客系列:备赛20周合集 20周的完整安排请点击:20周计划 每周发1个博客,共20周(读者可以按…...

数据增强让模型更健壮
在做一些图像分类训练任务时,我们经常会遇到一个很尴尬的情况,那就是: 明明训练数据集中有很多可爱猫咪的照片,但是当我们给训练好的模型输入一张戴着头盔的猫咪进行测试时,模型就不认识了,或者说识别精度很低。 很明显,模型的泛化能力太差,难道戴着头盔的猫咪就不是猫…...

Redis远程字典服务
1 介绍 Redis(Remote Dictionary Server)是一个开源的内存数据存储系统,可以用作数据库、缓存和消息中间件。它支持多种数据结构,包括字符串(strings)、哈希表(hashes)、列表&#…...

Hdoop学习笔记(HDP)-Part.15 安装HIVE
目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …...

vue3+element-plus之el-date-picker日期选择器清空无回调的解决方案
MENU 前言解决htmlJavaScrip 前言 在一个任务列表的搜索栏,添加一个日期区间搜索。使用到element-plus中的日期选择器el-date-picker;el-date-picker本身方法中有change事件,但是清空按钮没有对应回调方法。在任务列表的搜索需求中࿰…...

【虚拟机】Docker基础 【二】
2.2.数据卷 容器是隔离环境,容器内程序的文件、配置、运行时产生的容器都在容器内部,我们要读写容器内的文件非常不方便。大家思考几个问题: 如果要升级MySQL版本,需要销毁旧容器,那么数据岂不是跟着被销毁了&#x…...

CSS 绝对定位问题和粘性定位介绍
目录 1,绝对定位问题1,绝对定位元素的特性2,初始包含块问题 2,粘性定位注意点: 1,绝对定位问题 1,绝对定位元素的特性 display 默认为 block。所以行内元素设置绝对定位后可直接设置宽高。脱离…...

matlab 计算两点云之间的放缩倍数
目录 一、算法原理1、原理概述2、参考文献二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法原理 1、原理概述 放缩倍数即尺度参数,尺度参数可由2个公共点在不同坐标系下的距离之…...

MySQL-数据库设计与实现
目录 第1关:从概念模型到MySQL实现 第2关:从需求分析到逻辑模型 第3关:建模工具的使用 第1关:从概念模型到MySQL实现 任务描述 将已建好的概念模型,变成MySQL物理实现。 # 请将你实现flight_booking数据库的语句写…...

后端返回图片流前端展示图片
根据后端返回的图片流格式,选用合适方法转换 下面以base64为例 if(res.status 200) {res.data.data.forEach((item,index) > {let Array data:image/png;base64, itemlet blob this.base64toBlob(Array)let url URL.createObjectURL(blob)this.imageList.p…...

解决 from . import _imaging as core ImportError: DLL load failed: 找不到指定的模块。
升级pillow版本就完事了 卸载掉之前的旧版本 conda uninstall pillow升级到新的版本就解决了 pip uninstall pillow 那个错误就解决了...

springBoot3.2 + jdk21 + GraalVM上手体验
springBoot3.2 jdk21 GraalVM上手体验 SpringBoot2.x官方已经停止维护了,jdk8这次真的得换了🤣 可以参考官方文章进行体验:https://spring.io/blog/2023/09/09/all-together-now-spring-boot-3-2-graalvm-native-images-java-21-and-virt…...

Python float(input())的用法,web中的应用
float(input()) 要理解Python中的float(input()),可以分两部分。第一,input()用于获取键盘上的输入,该函数的返回值是一个Python字符串str类型的数据——不过输入的是什么;第二,float()函数用于将传递的参数——这里就…...

uniapp是否可以用elementUI等前端UI库、使用步骤以及需要注意的问题
文章目录 uniapp是否可以用elementUI等前端UI库使用方法和步骤问题如何解决 uniapp是否可以用elementUI等前端UI库 在PC端开发uniapp,可以用elementUI,因为elementUI就是PC端的。 在使用uniapp,选择vue2.0时,实测可以用nodejs16的…...

在vue中如何书写 SSR 友好的代码
文章目录 前言服务端的响应性组件生命周期钩子访问平台特有 API跨请求状态污染激活不匹配自定义指令teleports后言 前言 hello world欢迎来到前端的新世界 😜当前文章系列专栏:vue.js 🐱👓博主在前端领域还有很多…...

开源与闭源:数字时代大模型之辩
欢迎大家到我的博客浏览更多文章。YinKais Blog | YinKais Blog 大模型的未来:开源与闭源的博弈 在大模型的发展中,开源和闭源两种截然不同的开发模式发挥着重要的作用。开源以其技术共享的特性,吸引了大量人才参与,推动了大模型的…...

卷积神经网络(VGG-16)猫狗识别
文章目录 一、前言二、前期工作1. 设置GPU(如果使用的是CPU可以忽略这步)2. 导入数据3. 查看数据 二、数据预处理1. 加载数据2. 再次检查数据3. 配置数据集4. 可视化数据 三、构建VG-16网络四、编译五、训练模型六、模型评估七、保存and加载模型八、预测…...

Mysql 行转列,把逗号分隔的字段拆分成多行
目录 效果如下源数据变更后的数据 方法第一种示例SQL和业务结合在一起使用 第二种示例SQL和业务结合在一起使用 结论 效果如下 源数据 变更后的数据 方法 第一种 先执行下面的SQL,看不看能不能执行,如果有结果,代表数据库版本是可以的&…...

基于单片机设计的智能水泵控制器
一、前言 在一些场景中,如水池、水箱等水体容器的管理中,保持水位的稳定是至关重要的。传统上,人们通常需要手动监测水位并进行水泵的启停控制,这种方式不仅效率低下,还可能导致水位过高或过低,从而对水体…...

反转链表的实现
题目描述: 给出一个链表的头节点,将其反转,并返回新的头节点 思路1:反转地址 将每个节点里的地址由指向下一个节点变为指向前一个节点 定义三个结构体指针n1,n2,n3,n1表示改后指针的地址,n2表示要修改结构体里next的…...

python之pyqt专栏6-信号与槽2
上一篇python之pyqt专栏5-信号与槽1-CSDN博客,我们通过信号与槽实现了点击Button,改变Label的文本内容。可以知道 信号是在类中定义的,是类的属性 槽函数是信号通过connect连接的任意成员函数,当信号发生时,执行与信号…...

C语言中一些特殊字符的输出
目录 %的介绍 斜杠与反斜杠 转义字符 %的介绍 int a1; 1、printf(’’%d’’,a);//输出1 2、printf(’’%%d’’,a);//输出%d 3、printf(’’%%%d ‘’,a)//输出%1 C语言中,%也是转义符,%%相当于% 斜杠与反斜杠 首先需要明白…...

Opencv制作电子签名(涉及知识点:像素过滤,图片通用resize函数,像素大于某个阈值则赋值为其它的像素值)
import cv2def resize_by_ratio(image, widthNone, heightNone, intercv2.INTER_AREA):img_new_size None(h, w) image.shape[:2] # 获得高度和宽度if width is None and height is None: # 如果输入的宽度和高度都为空return image # 直接返回原图if width is None:h_ratio …...

【漏洞复现】大华智慧园区综合管理平台deleteFtp接口远程命令执行
漏洞描述 大华智慧园区综合管理平台deleteFtp接口存在远程命令执行,攻击者可利用该漏洞执行任意命令,获取服务器控制权限。 免责声明 技术文章仅供参考,任何个人和组织使用网络应当遵守宪法法律,遵守公共秩序,尊重社会公德,不得利用网络从事危害国家安全、荣誉和利益…...

Unity Image - 镜像
1、为什么要使用镜像 在游戏开发过程中,我们经常会为了节省 美术图片资源大小,美术会将两边相同的图片进行切一半来处理。如下所示一个按钮 需要 400 * 236,然而美术只需要切一张 74*236的大小就可以了。这样一来图集就可以容纳更多的图片。…...

深入Spring Security魔幻山谷-获取认证机制核心原理讲解(新版)
文/朱季谦 这是一个古老的传说。 在神秘的Web系统世界里,有一座名为Spring Security的山谷,它高耸入云,蔓延千里,鸟飞不过,兽攀不了。这座山谷只有一条逼仄的道路可通。然而,若要通过这条道路前往另一头的…...

【知网稳定检索】第九届社会科学与经济发展国际学术会议 (ICSSED 2024)
第九届社会科学与经济发展国际学术会议 (ICSSED 2024) 2024 9th International Conference on Social Sciences and Economic Development 第九届社会科学与经济发展国际学术会议(ICSSED 2024)定于2024年3月22-24日在中国北京隆重举行。会议主要围绕社会科学与经济发展等研究…...