C++修炼之路之string模拟实现

news/2024/5/19 1:33:55/文章来源:https://blog.csdn.net/Miwll/article/details/137592080

目录

前言

一:构造函数+析构函数+拷贝构造函数

二:c_str +  size  +   capacity  +   operator= +    operator[]

三:普通迭代器 +const迭代器+范围for

四:关系操作符重载 

 五:reserve+resize

六:push_back  +  append  +  operator+=   +

七:insert+erase+swap+find+clear 

八:重载cin和cout 

九:整体代码

 十:总结


接下来的日子会顺顺利利,万事胜意,生活明朗-----------林辞忧

前言

在经过前面的对标准库中string类的各接口函数的简单介绍和使用后,接下来我们就将介绍关于模拟实现一个string类,去更深层次的了解标准库中string的实现,帮助我们更加了解string类,提升代码能力

一:构造函数+析构函数+拷贝构造函数

1.对于模拟实现sting 类的构造函数和拷贝构造函数时,定义的成员变量是const char *str的话,刚好适合拷贝构造函数,但对于后续的resize和reserve开空间这些等就将出现错误,还有使用c_str(c语言str系列函数都会解引用字符串str的)打印字符串时,对于无参构造的string类对象,使用const char *str的话,会直接解引用空指针的,还有const修饰的字符串时不允许修改的,所以要开辟的空间需要我们自己new出来,定义为char *str

2.对于拷贝构造函数我们不写的话,编译器默认实现的是浅拷贝(按照字节一个一个字节的拷贝),对于内置类型浅拷贝是没问题的,但对于自定义类型浅拷贝会出现错误,这里会有两个char*指针指向同一块空间,当一个修改时另一个也为会跟着修改,而且还会析构两次,直接出错,因此就需要我们自己实现深拷贝解决

3.当实现一个无参构造和一个传参构造时,为了简化我们可以考虑实现成一个带缺省值的构造函数

对于这些问题我们更好地实现方式为

	/*string()//无参构造:_str(new char[1]),_size(0),_capacity(0){_str[0] = '\0';}string(const char *str)//传参构造:_size(strlen(str)){_capacity = _size + 1;_str = new char[_capacity+1];strcpy(_str,str);}*///给缺省值的构造//string(const char *str=nullptr)//下面的strlen会进行解引用报错//string(const char *str='\0')//'\0'的ASCII码为0,直接接引用报错//string (const char *str="\0")//字符串的形式,可以string(const char* str = ""):_size(strlen(str)){_capacity = _size==0? 3:_size;//如果_size为0的话,下面开空间_size*2的话还是0会出错_str = new char[_capacity + 1];//开空间strcpy(_str, str);//传数据}~string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}string(const string& s)//拷贝构造:_size(s._size),_capacity(s._capacity){_str = new char[s._capacity + 1];strcpy(_str, s._str);}
private:char* _str;size_t _size;size_t _capacity;

二:c_str +  size  +   capacity  +   operator= +    operator[]

对于赋值重载可能存在的情况多样(是对已经定义的类对象的操作),主要的有以下几种

对于以上的三种情况下,我们可以分开讨论,但为了代码的不冗余,我们可以优化为直接开辟空间,拷贝数据,释放原空间,在指向新空间 ,但要注意d1=d1这种特殊情况的处理

//不修改成员变量数据的函数,尽量加const
const char* c_str()
{return _str;
}size_t size()const
{return _size;
}
size_t capacity()const
{return _capacity;
}
string& operator=(const string& s)//支持连续赋值
{if (this != &s)//处理d1=d1的情况{char* tmp = new char[s._capacity + 1];strcpy(tmp, s._str);delete[] _str;_str = tmp;_size = s._size;_capacity = s._capacity;}return *this;
}
const char& operator[](size_t pos)const//const对象的调用
{assert(pos < _size);return _str[pos];
}
char& operator[](size_t pos)//普通对象的调用
{assert(pos < _size);return _str[pos];
}

三:普通迭代器 +const迭代器+范围for

这里的迭代器我们实现为指针的方式,依然是左闭右开的规则,对于范围for其实在底层是转换为迭代器来实现的,所以实现了迭代器也就支持了范围for

const对象要用const迭代器来实现遍历,普通对象要调用普通迭代器或者const迭代器来实现遍历

typedef char* iterator;//普通迭代器
typedef const char* const_iterator;//const迭代器
iterator begin()
{return _str;
}
iterator end()
{return _str + _size;
}const_iterator begin() const
{return _str;
}
const_iterator end() const
{return _str + _size;
}
void Print(const string& s)
{//三种遍历方式for (size_t i = 0; i < s.size(); i++){cout << s[i] << " ";}cout << endl;string::const_iterator it = s.begin();while (it != s.end()){cout << *it << " ";it++;}cout << endl;for (auto ch : s){cout << ch << " ";}cout << endl;
}
void teststring2()
{string s1;string s2("hello world");s1 = s2;string::iterator it = s1.begin();while (it != s1.end()){cout << *it << " ";it++;}cout << endl;for (auto ch : s2){cout << ch << " ";}cout << endl;Print(s2);
}

四:关系操作符重载 

bool operator==(const string&s)const
{return strcmp(_str, s._str) == 0;
}
bool operator>(const string& s)const
{return strcmp(_str, s._str) > 0;
}
bool operator >=(const string& s)const
{return (*this == s) || (*this > s);
}
bool operator!=(const string& s)const
{return !(*this == s);
}
bool operator<(const string& s)const
{return !(*this >= s);
}
bool operator<=(const string& s)const
{return !(*this > s);
}

 五:reserve+resize

reserve是开空间,resize是开空间并初始化,但这两个都要注意当开的新空间比capacity小时,不能修改capacity

void reserve(size_t n)
{if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}
}
void resize(size_t n, char ch = '\0')
{if (n < _size)//删除数据,保留前n个{_size = n;_str[_size] = '\0';}else{if (n > _capacity){reserve(n);}size_t i = _size;while (i < n){_str[i] = ch;++i;}_size = n;_str[_size] = '\0';}
}

六:push_back  +  append  +  operator+=   +

在插入数据时需要时刻注意capacity,当capacity不足时,需要及时reserve扩容

void push_back(char ch)
{if (_size + 1 > _capacity){reserve(_capacity*2);}_str[_size] = ch;_size++;_str[_size] = '\0';//insert(_size,ch);
}
void append(const char* s)
{size_t len = strlen(s);if (_size + len > _capacity){reserve(_size + len);}strcpy(_str + _size, s);_size += len;//insert(_size,s);
}
string& operator+=(char ch)
{push_back(ch);return *this;
}
string& operator+=(const char* str)
{append(str);return *this;
}

七:insert+erase+swap+find+clear 

对于任意位置插入和删除,需要特别关注边界问题,插入需要及时关注capacity,及时扩容

对于插入需要注意size_t 类型会出现的一些问题,当要头插数据时,这时按照以前的方式移动的话,当pos=-1时停止,但size_t 类型的-1是整形最大值,所以要错位移动

string& insert(size_t pos, char ch)
{assert(pos <= _size);if (_size + 1 > _capacity){reserve(_capacity * 2);}//这样的移动会发生错误的/*size_t end = _size;while (end >= pos){_str[end + 1] = _str[end];--end;}*/size_t end = _size + 1;while (end >pos){_str[end] = _str[end - 1];--end;}_str[pos] = ch;++_size;return *this;
}
string& inster(size_t pos,const char* str)
{assert(pos <= _size);size_t len = strlen(str);if (_size + len > _capacity){reserve(_size + len);}size_t end = _size + len;//挪动数据while (end >= pos + len){_str[end] = _str[end - len];--end;}//插入拷贝strncpy(_str + pos, str, len);_size += len;return *this;
}
string& erase(size_t pos, size_t len = npos)
{if (pos == npos || pos+len>=_size){_str[pos] = '\0';_size = pos;}else{strcpy(_str + pos, _str + pos + len);_size -= len;}return *this;
}void swap(string& s)
{std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);
}size_t find(const char* str, size_t pos = 0)
{assert(pos <= _size);char* tmp = strstr(_str + pos, str);if (tmp == nullptr){return npos;}return tmp - _str;
}
void clear()
{_str[0] = '\0';_size = 0;
}

八:重载cin和cout 

ostream& operator<<(ostream& out,const string &str)
{for (auto ch : str){out << ch;}return out;
}
istream& operator>>(istream& in, string& s)
{s.clear();char ch = in.get();char buff[128];size_t i = 0;while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == 127){buff[127] = '\0';s += buff;i = 0;}ch = in.get();}if (i != 0){buff[i] = '\0';s += buff;}return in;
}
}

九:整体代码

https://gitee.com/lin-ciyu/cplusplus/tree/master/string2/string2

 十:总结

关于string的模拟实现就到这里了,里面有许多细节需要注意的,多练多去感受

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

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

相关文章

【C++第三阶段】deque容器评委打分案例

以下内容仅为当前认识&#xff0c;可能有不足之处&#xff0c;欢迎讨论&#xff01; 文章目录 构造函数赋值操作大小操作插入删除数据存取排序评委评分案例描述 deque容器 双端数组&#xff0c;可以对头端插入删除操作。 如下图所示。 头部有插入删除操作&#xff0c;尾部亦然…

three.js尝试渲染gbl模型成功!(三)

参照教程&#xff1a;https://cloud.tencent.com/developer/article/2276766?areaSource102001.5&traceId88k805RaN_gYngNdKvALJ &#xff08;作者&#xff1a;九仞山&#xff09; 通过最近两天查three.js入门教程了解到 这玩应支持包括 .obj、.gltf等类型的模型结构。 g…

【微服务】------服务注册

在 微服务的基建工作 中提到过&#xff0c;在云原生、微服务时代&#xff0c;如果还是手动修改服务地址&#xff0c;是几乎不可完成的工作&#xff0c;需要一种机制完成自动上报和获取服务地址的支撑组件&#xff0c;可以保障服务的快速上线和下线&#xff0c;这就是服务注册/发…

vue vue3 手写 动态加载组件

效果展示 一、需求背景&#xff1a; # vue3 项目涉及很多图表加载、表格加载 #考虑手写一个动态加载组件 二、实现思路 通过一个加载状态变量&#xff0c;通过v-if判断&#xff0c;加载状态的变量等于哪一个&#xff0c;动态加载组件内部就显示的哪一块组件。 三、实现效果…

酷开科技 |酷开系统全视频化升级,让电视回归视频属性

随着消费升级浪潮的兴起&#xff0c;家庭互联网这一概念也在资本的注入下&#xff0c;成为了新风口。酷开系统全视频化升级&#xff0c;让电视回归视频属性&#xff0c;酷开系统在之前瀑布流板块设计的基础上&#xff0c;增加了视频流图文融合的并行界面&#xff0c;同时酷开系…

AWS入门实践-利用S3构建一个静态网站

使用Amazon S3托管静态网站是一个流行的选择&#xff0c;因为它简单、成本效益高&#xff0c;并且易于维护。静态网站由不含服务器端脚本的文件组成&#xff0c;如HTML、CSS和JavaScript文件。下面是使用S3托管静态网站的操作步骤&#xff1a; 如果大家没有AWS免费账号&#x…

外包干了15天,技术倒退明显

先说情况&#xff0c;大专毕业&#xff0c;18年通过校招进入湖南某软件公司&#xff0c;干了接近6年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落&#xff01; 而我已经在一个企业干了四年的功能…

ITK 重采样 resample

Itk 重新采样有二多种情况&#xff0c;这里说二种情况 1. 输入参数 &#xff0c;和输出相关数据&#xff0c;输出范围&#xff0c;spacing &#xff1b; typedef itk::Image< float, 3 > itkFloatImageType;typedef itk::ResampleImageFilter < itkFloatImageType, i…

数字化智慧养老:引领老年人融入科技时代新生活

hello宝子们...我们是艾斯视觉擅长ui设计和前端开发10年经验&#xff01;希望我的分享能帮助到您&#xff01;如需帮助可以评论关注私信我们一起探讨&#xff01;致敬感谢感恩&#xff01; 人类社会已经步入了一个全新的数字时代。在这个时代&#xff0c;互联网、大数据、人工智…

搭建前后端的链接(java)

搭建前后端的链接(java) 一.前提 1.1 javaEE 搭建前后端的链接首先需要用到javaEE&#xff0c;也就是java企业版&#xff0c;也就是java后端(后端javaSE) 利用javaEE和前端交互&#xff0c;javaSE和数据库交互&#xff0c;javaSE和javaEE之间再进行交互就实现了前后端的交互…

“卷生卷死”的消费电子ODM,如何用数据建设缩短交期?奇点云供应链控制塔实践

消费电子制造是一个充分竞争的行业。 哪怕对于已位居全球龙头的ODM厂商&#xff08;原始设计制造商&#xff09;而言&#xff0c;在既卷质量又卷价格还卷创新的市场始终保持领先&#xff0c;也从不简单。 以本文分享的企业为例&#xff0c;企业A是领先的智能硬件ODM厂商&…

scRAN-seq|加权最近邻分析(2)

概述 本文[1]介绍了Seurat 5.0.0中的加权最近邻&#xff08;WNN&#xff09;分析方法&#xff0c;这是一种用于整合和分析多模态单细胞数据的无监督框架。 简介 多模态分析作为单细胞基因组学的一个新兴领域&#xff0c;它通过同时测量多种数据类型来精确描绘细胞状态&#xff…

掼蛋的六讲原则

第一讲&#xff1a;与同事玩掼蛋&#xff0c;讲娱乐 同事可以说是现在的人们见得最多的一批人&#xff0c;所以与同事打好关系是十分有必要的&#xff0c;所以在和同事玩掼蛋的时候&#xff0c;我们主要讲究的是娱乐精神&#xff0c;大家一起开开心心玩&#xff0c;工作也能变得…

Docker快速上手及常用命令速查

Docker快速上手 安装 在ubuntu上安装docker: sudo apt-get install docker docker -v #查看版本在centos7上安装docker&#xff1a;(docker在YUM源的Extras仓库中) yum install docker systemctl start dockerdocker常用命令速查 #查看docker信息 docker info #查看本地镜…

SpringBoot及其特性

0.前言 Spring 框架提供了很多现成的功能。那么什么是 Spring Boot&#xff1f;使用 Spring 框架&#xff0c;我们可以避免编写基础框架并快速开发应用程序。为了让 Spring 框架提供基础框架&#xff0c;我们需要向 Spring 框架描述有关我们的应用程序及其组件的信息。 不只是…

面试记录(三)

面了57min&#xff0c;实在问麻了&#xff0c;下面的问题就没有按顺序记录了&#xff1a; 1.linux熟悉吗&#xff1a;熟悉基础的环境变量、目录等用法&#xff0c;问如何查找一个文件&#xff08;不会&#xff0c;又追问如何设计一个c的程序去查找&#xff1a;先找文件类型&am…

java基础语法(12)| 异常

1. 异常 1.1 什么是异常 异常 &#xff1a;指的是程序在执行过程中&#xff0c;出现的非正常的情况&#xff0c;最终会导致JVM的非正常停止。 在Java等面向对象的编程语言中&#xff0c;异常本身是一个类&#xff0c;产生异常就是创建异常对象或抛出了一个异常对象。Java处理异…

万界星空科技生产工时管理系统

生产工时管理系统是一个管理系统&#xff0c;生产管理人员可以详细地、逐项活动地查看生产和即时劳动力数据&#xff0c;特别是活动级劳动力信息&#xff0c;辅助生产管理人员利用从车间获得的效率数据&#xff0c;实时监控生产流程&#xff0c;并在提高生产率&#xff0c;控制…

C++的并发世界(十一)——线程池

0.线程池的概念 1.线程池使用步骤 ①初始化线程池&#xff1a;确定线程数量&#xff0c;并做好互斥访问&#xff1b; ②启动所有线程 ③准备好任务处理基类&#xff1b; ④获取任务接口&#xff1a;通过条件变量阻塞等待任务 2.atomic原子操作 std:atomic是C11标准库中的一个…

ics-05-攻防世界

题目 点了半天只有设备维护中心能进去 御剑扫一下 找到一个css 没什么用 再点击云平台设备维护中心url发生了变化 设备维护中心http://61.147.171.105:65103/index.php?pageindex试一下php伪协议 php://filter/readconvert.base64-encode/resourceindex.php base64解一下…