【C++】——string模拟实现

前言

string的模拟实现其实就是增删改查,只不过加入了类的概念。

为了防止与std里面的string冲突,所以这里统一用String。

目录

前言

一   初始化和销毁 

1.1  构造函数

1.2  析构函数

 二  迭代器实现

三  容量大小及操作

 四 运算符重载

 4.1  bool operator<(const String& s) const

4.2  bool operator==(const String& s) const 

 4.3  bool operator<=(const String& s) const

4.4 bool operator>(const String& s) const

4.5  bool operator>=(const String& s) const 

 4.6  bool operator!=(const String& s) const

 五  字符串操作 

5.1  截取操作

5.2  查找操作

六  流插入流提取

6.1  ostream& operator<<(ostream& out, const String& s)

6.2   istream& operator>>(istream& in, String& s)

 七  string与string相加

String operator+(const String& s2)

string类模拟实现完整代码

总结


一   初始化和销毁 

1.1  构造函数

对于构造函数来说有有参构造和无参构造

所以直接把他们结合起来

default 
string();
copy 
string (const string& str);

 1.string();//无参构造

2.string (const string& str);//有参构造

String(const char* str = "") :_size(strlen(str)), _capacity(_size){_str = new char[_capacity+1];strcpy(_str, str);}

 如果把_str的初始化放在初始化列表会出问题

private:char* _str;size_t _size;size_t _capacity;static const size_t npos = -1;
String(const char* str = "") :_str(new char [_capacity+1]),_size(strlen(str)), _capacity(_size){//_str = new char[_capacity+1];strcpy(_str, str);}

初始化列表是会按照成员变量的顺序去初始化,所以这里 初始化_str,_capacity没有初始化,所以在开空间的时候会出问题,当然你可以换一换位置,但是未免太繁琐,同时这里不能把_str设置为nullptr,如果设置为空,那么_size正初始化就会出问题

1.2  析构函数

 这里的析构函数没有那么多细节,直接释放空间,然后处理其他的成员变量就行了

~String(){delete[] _str;//注意这里的delete[],不是delete_str = nullptr;_size = 0;_capacity = 0;}

 二  迭代器实现

其实迭代器可以理解为是指针在进行,有的底层是指针有的是其他的方法,这里我们用指针去模拟实现

//迭代器typedef char* iterator;typedef char* const_iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}const_iterator begin()const{return _str;}const_iterator end()const{return _str + _size;}

迭代器也需要const类型,这样const类型的函数才能去调用,所以写两份。注意范围for就是无脑替换迭代器,本质和迭代器是一样的。

测试案例

#define _CRT_SECURE_NO_WARNINGS 1
#include"String.h"
int main()
{String str("Test string");for (String::iterator it = str.begin(); it != str.end(); ++it)cout << *it;cout << '\n';for (auto ch : str){cout << ch << " ";}cout << endl;return 0;
}

还有反向迭代器,这里就不一一列举了,想了解的可以参考string类的介绍

三  容量大小及操作

1.capacity()//表示容量大小

2.size()//有效数据大小

3.max_size()//最大有多少数据

4.empty()//是否为空

5.resize()//扩容

6.reserve()//扩容

size_t size()const{return _size;}size_t capacity()const{return _capacity;}size_t max_size()const{return 4294967291;}bool empty()const {return _size == 0;}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){_str[n] = '\n';_size = n;}else{reserve(n);while (_size < n){_str[_size] = ch;_size++;}_str[_size] = '\0';}}

1.对于empty,它是如果为空,才是真,不为空就假

2.对于resize和reserve来说,从参数列表可以看出,resize可以设置初始值,也就是可以改变_size,

但是reserve不行,同时reserve设置的n如果比capacity小的话,是不会造成任何影响或者改变的

3.这里的max_size,这里我设置了一个常量,但是并没有这么简单,因为max_size是根据你当前系统来判断该给多大的,因素很多,但是实现起来很麻烦,这里就简单的设置为初始值了

测试案例

由于其他的测试在之前的string类博客测试过了,所以这里就不一一测试了

#define _CRT_SECURE_NO_WARNINGS 1
#include"String.h"
int main()
{String str("Test string");cout << "size: " << str.size() << "\n";cout << "capacity: " << str.capacity() << "\n";cout << "max_size: " << str.max_size() << "\n";return 0;
}

 

 四 运算符重载

 运算符重载就是>,<,=,>=,<=这四种,但是其实写一个大于和等于或者写一个小于和等于就行了,因为其他的都能复用

 4.1  bool operator<(const String& s) const
bool operator<(const String& s) const{return strcmp(_str, s._str) < 0;}

4.2  bool operator==(const String& s) const 
bool operator==(const String& s) const{return strcmp(_str, s._str) == 0;}

由于上面写了<和=的运算符重载,所以下面这几个直接复用前面的东西就行, 注意上面的写法用的是字符串函数进行比较,但是库里面用的是模板,所以这里有出入,如果用模板,就不能这样比较了

 4.3  bool operator<=(const String& s) const
bool operator<=(const String& s) const{return *this < s || *this == s;}
4.4 bool operator>(const String& s) const
bool operator>(const String& s) const{return !(*this <= s);}
4.5  bool operator>=(const String& s) const 
bool operator>=(const String& s) const{return !(*this < s);}
 4.6  bool operator!=(const String& s) const
bool operator!=(const String& s) const{return !(*this == s);}

 五  字符串操作 

5.1  截取操作

String substr(size_t pos = 0, size_t len = npos)const 

String substr(size_t pos = 0, size_t len = npos)const {assert(pos >= 0 && pos < _size);size_t end = len + pos;//最后的位置String s = "";if (len == npos || pos + len > _size)//如果长度已经大于当前字符串长度{len = _size - pos;//新长度就等于pos到_size这么长end = _size;//}s.reserse(len);//开辟空间for (int i = pos; i < end; i++)//从pos开始到end结束{s += _str[i];}return s;}

 测试样例:

5.2  查找操作

size_t find(char c, size_t pos = 0)const

size_t find(char c, size_t pos = 0)const{for (int i = pos;i < _size; i++){if (_str[i] = c){return i;}}return npos;}

查找一个字符 之间从pos位置开始遍历就行了

size_t find(const char* s, size_t pos = 0)const

	size_t find(const char* s, size_t pos = 0)const{char* p = strstr(_str + pos, s);if (p){return p - _str;}else{return npos;}}

查找一个字符直接用库函数strstr就行 

测试用例: 

 

 

六  流插入流提取

由于这里的流插入和流提取不会涉及到私有的成员变量,所以不用写成友员函数

6.1  ostream& operator<<(ostream& out, const String& s)
ostream& operator<<(ostream& out, const String& s)
{for (auto ch : s){out << ch;}return out;
}
6.2   istream& operator>>(istream& in, String& s)
//流提取
istream& operator>> (istream& in, string& s)
{s.clear();char ch = in.get();while (ch != ' ' && ch != '\n'){s += ch;ch = in.get();}return in;
}

对于上面这段代码来说,我们首先要用一个clear去清理一下,因为不清理会导致之前的数据存在。

还有一点就是这段代码并不好,因为读字符的时候可能会导致频繁的扩容,我们电脑上面的程序可不止一个,不能一直中断其他程序,来进行这个,这样对于计算机的消耗有点大

istream& operator>>(istream& in, String& s)
{char buff[129];size_t i = 0;char ch;ch = in.get();while (ch != ' ' && ch != '\0'){buff[i++] = ch;if (i == 128){buff[i] = '\0';s += buff;i = 0;}ch = in.get();}if (i > 0){buff[i] = '\0';s += buff;}return in;
}

这段代码就是对之前的一个改良,设置一个数组去存, 当存到128个字符的时候再一起把它放进字符串里面去,最后还有判断一下如果i!=128的情况即可

 七  string与string相加

String operator+(const String& s2)

这里用成员函数来写,库里面用的是非成员函数

String operator+(const String& s2){String ret;ret._size = _size + s2._size;ret._str = new char[_capacity + s2._capacity];strcpy(ret._str, _str);strcpy(ret._str + _size, s2._str);return ret;}

先开空间,然后把两个字符串放进去就行。

string类模拟实现完整代码

#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
class String
{
public://迭代器typedef char* iterator;typedef char* const_iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}const_iterator begin()const{return _str;}const_iterator end()const{return _str + _size;}//构造函数String(const char* str = "") :_size(strlen(str)), _capacity(_size){_str = new char[_capacity+1];strcpy(_str, str);}//析构函数~String(){delete[] _str;_str = nullptr;_size = 0;_capacity = 0;}//拷贝构造String(const String& s):_str(nullptr),_size(s._size), _capacity(s._capacity){_str = new char[_capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}//下表访问char& operator[](size_t pos){assert(pos < _size||pos>=0);return _str[pos];}void swap(String& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}//赋值运算符重载String&operator=(String tmp){swap(tmp);return *this;}//Capacitysize_t size()const{return _size;}size_t capacity()const{return _capacity;}size_t max_size()const{return 4294967291;}bool empty()const {return _size == 0;}void reserse(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){_str[n] = '\n';_size = n;}else{reserse(n);while (_size < n){_str[_size] = ch;_size++;}_str[_size] = '\0';}}//Element accesschar& back(){return _str[_size - 1];}const char& back()const{return _str[_size - 1];}char& front(){return _str[0];}const char& front()const {return _str[0];}//Modifiersvoid append(const char* str){size_t n = _size + strlen(str);if (n > _capacity){reserse(n);_capacity = n;}strcat(_str, str);_size += strlen(str);}void push_back(char ch){if (_size == _capacity){reserse(_capacity == 0 ? 4 : 2 * _capacity);}_str[_size] = ch;_size++;_str[_size] = '\0';}String& operator+=(const String& s){append(s._str);return *this;}String& operator+=(const char* str){append(str);return *this;}String& operator+=(char ch){push_back(ch);return *this;}void insert(size_t pos, char ch){assert(pos <= _size && pos >= 0);if (_size == _capacity){reserse(_capacity == 0 ? 4 : _capacity * 2);}size_t end = _size + 1;while (end > pos){_str[end] = _str[end-1];end--;}_str[pos] = ch;_size++;}void insert(size_t pos, const char* str){assert(pos <= _size && pos >= 0);int len = strlen(str);if (_size + len > _capacity){reserse(_size + len);}size_t end = _size+1;while (end > pos){_str[end + len] = _str[end-1];end--;}strncpy(_str + pos, str, len);_size += len;}void erase(size_t pos = 0, size_t len = npos){assert(pos >= 0 && pos < _size);if (len == npos||pos+len>_size){_str[pos] = '\0';_size = pos;}else{size_t end = pos + len;while (end <= _size){_str[end - len] = _str[end];end++;}_size -= len;}}//String operations:const char* c_str()const{return _str;}const char* data()const{return _str;}size_t find(char c, size_t pos = 0)const{for (int i = pos;i < _size; i++){if (_str[i] == c){return i;}}return npos;}size_t find(const char* s, size_t pos = 0)const{char* p = strstr(_str + pos, s);if (p){return p - _str;}else{return npos;}}String substr(size_t pos = 0, size_t len = npos)const {assert(pos >= 0 && pos < _size);size_t end = len + pos;String s = "";if (len == npos || pos + len > _size){len = _size - pos;end = _size;}s.reserse(len);for (int i = pos; i < end; i++){s += _str[i];}return s;}String operator+(const String& s2){String ret;ret._size = _size + s2._size;ret._str = new char[_capacity + s2._capacity];strcpy(ret._str, _str);strcpy(ret._str + _size, s2._str);return ret;}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);}
private:char* _str;size_t _size;size_t _capacity;static const size_t npos = -1;
};
//non_member constants
ostream& operator<<(ostream& out, const String& s)
{for (auto ch : s){out << ch;}return out;
}
istream& operator>>(istream& in, String& s)
{char buff[129];size_t i = 0;char ch;ch = in.get();while (ch != ' ' && ch != '\0'){buff[i++] = ch;if (i == 128){buff[i] = '\0';s += buff;i = 0;}ch = in.get();}if (i > 0){buff[i] = '\0';s += buff;}return in;
}

总结

以上就是string的全部内容了,💞。

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

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

相关文章

SpringCloud学习笔记(一)

SpringCloud、SpringCloud Alibaba 前置知识&#xff1a; 核心新组件&#xff1a; 所用版本&#xff1a; 学习方法&#xff1a; 1.看理论&#xff1a;官网 2.看源码&#xff1a;github 一、微服务理论知识 二、关于SpringCloud各种组件的停更/升级/替换 主业务逻辑是&#x…

中建环能 | “农村生活污水治理稳质增效与智能运维技术研究及成套装备应用” 科技成果评价

中华环保联合会组织召开了中建环能科技股份有限公司申请的“农村生活污水治理稳质增效与智能运维技术研究及成套装备应用”技术成果评价会。会议由中华环保联合会水环境治理专业委员会秘书长刘愿军主持。 评审会委员 本次评价会邀请了7位相关专业领域的专家组成专家评价委员会。…

977. 有序数组的平方 - 力扣

1. 题目 给你一个按 非递减顺序 排序的整数数组 nums&#xff0c;返回 每个数字的平方 组成的新数组&#xff0c;要求也按 非递减顺序 排序。 2. 示例 3. 分析 我们当然可以遍历数组平方元素&#xff0c;然后再使用sort排序&#xff0c;但这里时间复杂度就为 O(logN) 了。 我…

音视频开发—视频相关概念:YUV与RGB

文章目录 YUV相关概念组成部分优点常见的 YUV 格式数据量的计算YUV4:2:0 存储格式平面模式&#xff08;planar):打包模式&#xff08;packed&#xff09; RGB 和 YUV 的定义关系与转换RGB 到 YUV 的转换YUV 到 RGB 的转换 使用场景优缺点 YUV相关概念 YUV 是一种颜色编码格式&…

Linux--EXT2文件系统

参考资料&#xff1a; linux之EXT2文件系统--理解block/block group/索引结点inode/索引位图_一个块组中索引节点表和数据块区最多占用字节-CSDN博客 linux环境&#xff1a; Linux version 5.15.146.1-microsoft-standard-WSL2 (root65c757a075e2) (gcc (GCC) 11.2.0, GNU ld…

GPT-4o有点坑

GPT-4o有点坑 0. 前言1. GPT-4o简介2. GPT-4o带来的好处2.1 可以上传图片和文件2.2 更丰富的功能以及插件 3. "坑"的地方3.1 使用时间短3.2 GPT-4o变懒了 4. 总结 0. 前言 原本不想对GPT-4o的内容来进行评论的&#xff0c;但是看了相关的评论一直在说&#xff1a;技…

truncate IDL_UB1$导致数据库open hang---惜分飞

在一次数据库恢复中,发现IDL_UB1$表被truncate,然后数据库在open过程中会hang住,而且不报任何错误,这里通过试验进行重现.对于这类问题,以前有过类似处理测试&#xff1a;truncate IDL_UB1$恢复试验数据库版本 SQL> select * from v$version; BANNER ---------------------…

vue3学习(六)

前言 接上一篇学习笔记&#xff0c;今天主要是抽空学习了vue的状态管理&#xff0c;这里学习的是vuex&#xff0c;版本4.1。学习还没有学习完&#xff0c;里面有大坑&#xff0c;难怪现在官网出的状态管理用Pinia。 一、vuex状态管理知识点 上面的方式没有写全&#xff0c;还有…

对象转为Map

方案一&#xff0c;Jackson String json objectMapperFace.writeValueAsString(contract);Map<String,Object> map objectMapperFace.readValue(json, Map.class);方案二 &#xff0c; apache BeanUtils Map<String,String> beanMap null;try {beanMap BeanUti…

MyBatis延迟加载缓存分页逆向工程

文章目录 延迟加载概述步骤 缓存一级缓存介绍原理 二级缓存介绍 设置缓存对象策略原理开启步骤属性解释是否使用一级缓存 分页插件使用步骤 逆向工程介绍搭建使用增删修改查 延迟加载 概述 延迟加载本身是依赖于多表查询的 延迟加载中返回值要选择resultMap返回的结果一定是D…

Docker管理工具Portainer忘记admin登录密码

停止Portainer容器 docker stop portainer找到portainer容器挂载信息 docker inspect portainer找到目录挂载信息 重置密码 docker run --rm -v /var/lib/docker/volumes/portainer_data/_data:/data portainer/helper-reset-password生成新的admin密码&#xff0c;使用新密…

分享6个打开就能让人眼前一亮的网站,每次浏览都像发现新大陆~

1、ZLibrary zh.zlibrary-be.se/ ZLibrary是一个广受欢迎的在线图书馆&#xff0c;它提供了一个庞大的电子书和文章资源库&#xff0c;数量超过千万。这个平台覆盖了国内外众多领域的电子书资源&#xff0c;几乎可以满足用户98%以上的搜索需求&#xff0c;无论是学术研究、文…

【介绍下运维,什么是运维?】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

大数据开发面试题【Mysql篇】

181、mysql数据库中的引擎 用于数据存储、处理和保护数据的核心服务&#xff0c;不同的数据库引擎有其各自的特点&#xff0c;常见的引擎&#xff1a;InnoDB&#xff0c;Mylsam、Memory、Mrg_Mylsam、Blackhole innodb&#xff1a;是一个事务性存储引擎&#xff0c;提供了对事…

C++的第一道门坎:类与对象(一)

目录 1.面向过程与面向对象 1.1面向过程 1.2面向对象 1.3对比 2.类的引入 2.1类的声明方式 2.2类的成员的两种定义方式 2.2.1单文件定义 2.2.2多文件定义 3.类的访问限定符与封装 3.1访问限定符 3.2封装 4.类对象 4.1类对象的实例化 4.2类对象的存储 4.2.1 存储…

高并发项目-分布式Session解决方案

分布式Session解决方案 1.保存Session&#xff0c;进入商品列表页面 1.保存Session 1.编写工具类 1.MD5Util.java package com.sxs.seckill.utils;import org.apache.commons.codec.digest.DigestUtils;/*** Description: MD5加密工具类** Author sun* Create 2024/5/5 14…

Window系统安装Docker

因为docker只适合在liunx系统上运行&#xff0c;如果在window上安装的话&#xff0c;就需要开启window的虚拟化&#xff0c;打开控制面板&#xff0c;点击程序&#xff0c;在程序和功能中可以看到启动和关闭window功能&#xff0c;点开后&#xff0c;找到Hyper-V&#xff0c;Wi…

【环信IM集成教程】分分钟带你实现视频消息的在线播放和本地播放

有种需求&#xff0c;叫下班前实现 发送视频消息是即时通讯应用中很常见的功能&#xff0c;现在的视频播放场景五花八门&#xff0c;眼瞅快下班&#xff0c;接到产品需求 如何实现这个需求&#xff0c;好准点下班回家抢显卡 &#xff0c;快速提升自己的工作效率&#xff0c;那…

yolov5-ros模型结合zed2相机部署在 Ubuntu系统

前言 本篇文章主要讲解yolov5-ros模型结合zed2相机进行实时检测&#xff0c;经改进实现了红绿灯检测&#xff0c;并输出检测类别与置信度&#xff01; 目录 一、环境配置二、zed2驱动安装三、yolov5-ros功能包配置四、运行官方权重文件四、运行自己权重文件 一、环境配置 1、…

vue2转vue3初步下载pnpm遇到的问题 pnpm : 无法加载文件 D:\nodejs\pnpm.ps1

安装pnpm npm install -g pnpm pnpm -v 提示&#xff1a; 解决&#xff1a;nvm install 18.18.0 下载最稳定版本的nodejs nvm use 18.18.0 然后注意重新下载删除pnpm npm uninstall -g pnpm npm install -g pnpmlatest 在vscode使用pnpm报错 解决&#xff1a;管理员运行Windo…