当前位置: 首页 > news >正文

string(2)

这篇文章主要是用自己的方式实现string类的一些重要接口,以便大家知道string类的各接口是如何实现其功能的,文章末尾会给出完整代码。

一.准备工作

我们要自定义string类,为了不让其与标准库的string名冲突,因此我们需要创造有个命名空间域,将自定义类的声明和实现写在这个域中,像这样:

namespacemy{classstring{public://函数声明voidpush_back(constcharc);voidappend(constchar*s);string&operator+=(constcharc);string&operator+=(constchar*s);voidinsert(size_t pos,constcharc);voidinsert(size_t pos,constchar*s);voiderase(size_t pos,size_t len=npos);// nopssize_tfind(charch,size_t pos=0);size_tfind(constchar*str,size_t pos=0);stringsubstr(size_t pos=0,size_t len=npos);private:char*_str;size_t _size;size_t _capacity;staticconstsize_t npos=-1;//一般来说,类中的ststic成员变量不能给缺省值//但是,前面是static const的整形可以加缺省值}}

二.接口实现

1.构造和析构函数
//默认构造string(constchar*s="")//相当于传来个'/0'{_size=strlen(s);_capacity=_size;//它是不包括'/0'的_str=newchar[_capacity+1];//要开一个给'/0'strcpy(_str,s);//遇到'/0'会停,并且自动把'/0'带上}//拷贝构造string(string&s){_size=strlen(s._str);_capacity=_size;_str=newchar[_capacity+1];strcpy(_str,s._str);}//析构函数~string(){delete[]_str;_str=nullptr;_size=_capacity=0;}

new[]与delete[]一定要配套使用。

2.实行容量操作的函数
//清空有效数据voidclear(){_str[0]=0;_size=0;}//获取字符串变量constchar*c_str()const{returnthis->_str;}//获取有效数据个数size_tsize()const{return_size;}//获取容量size_tcapacity()const{return_capacity;}//预留空间voidreserve(size_t n){if(n<=_capacity)return;//不减少空间char*tmp=newchar[n+1];strcpy(tmp,_str);delete[]_str;_str=tmp;_capacity=n;}
3.增删查改

重载[],可以让string类中的数据可以跟字符串的一样用[]访问

char&operator[](size_t pos)//这里虽然不会改this内容,但不能加const,//因为要和下面的参数类型区分开{assert(pos<_size);return_str[pos];}constchar&operator[](size_t pos)const{assert(pos<_size);return_str[pos];}

重载赋值运算

string&operator=(conststring&str){if(&str!=this){delete[]_str;_str=newchar[strlen(str._str)];strcpy(_str,str._str);_size=str._size;_capacity=str._capacity;}return*this;}

尾插字符

voidstring::push_back(constcharc){if(_size==_capacity)//检查容量是否够用{size_t newcapacity=(_capacity==0?4:2*_capacity);reserve(newcapacity);}_str[_size]=c;_size++;_str[_size]=0;}

尾插字符串

voidstring::append(constchar*s){size_t len=strlen(s);if(_size+len>_capacity)//检查容量是否够用{size_t newcapacity=(_capacity+len>2*_capacity?_capacity+len:2*_capacity);//新的容量大小reserve(newcapacity);}for(inti=0;i<len;i++)//这里也可以用strcpy{_str[_size++]=s[i];}_str[_size]=0;}

重载+=字符或字符串,直接调用尾插即可

string&string::operator+=(constcharc){this->push_back(c);return*this;}string&string::operator+=(constchar*s){this->append(s);return*this;}

从指定位置插入字符

//pos是插入的值所在位置,需要移动pos后的值voidstring::insert(size_t pos,constcharc){assert(pos<=_size);if(_size==_capacity)//检查容量{size_t newcapacity=(_capacity==0?4:2*_capacity);reserve(newcapacity);}size_t end=_size+1;//把'/0'同时移了while(end>pos-1)//要把pos位置的值一起移了//用memmove也可以{_str[end]=_str[end-1];end--;}_str[pos]=c;++_size;}

在指定位置插入字符串

voidstring::insert(size_t pos,constchar*s){assert(pos<=_size);size_t len=strlen(s);if(_size+len>_capacity){size_t newcapacity=(_capacity+len>2*_capacity?_capacity+len:2*_capacity);reserve(newcapacity);}size_t end=_size+len;while(end>len+pos-1)//这样可以使两边都不到-1{_str[end]=_str[end-len];end--;}//把pos及其之后的数据向后移/*for (int i = 0; i < len; i++) { _str[pos + i] = s[i]; }*/memmove(_str+pos,s,len);//不会自动带"/0"_size+=len;}

删除指定位置(包括)后的n个数据

voidstring::erase(size_t pos,size_t len)//在类声明中写了缺省值这里就不能写了{assert(pos<_size);if(len>=_size-pos){_str[pos]=0;_size=pos;}else{while(pos+len<_size)//可以用memmove{_str[pos]=_str[pos+len];pos++;}_str[pos]=0;}}

查找字符

size_t string::find(charch,size_t pos)//从pos开始找ch{assert(pos<_size);for(size_t i=pos;i<_size;i++){if(_str[i]==ch)returni;}returnnpos;}

查找字符串

size_t string::find(constchar*str,size_t pos){assert(pos<_size);constchar*ptr=strstr(_str+pos,str);if(!ptr)returnnpos;returnptr-_str;}

获取字符串从pos开始的len个字符

string string::substr(size_t pos,size_t len)//实现这个函数必须要有构造函数,因为会返回临时类变量{assert(pos<_size);if(pos+len>_size)len=_size-pos;string ret;ret.reserve(len);strncpy(ret._str,_str,len);ret._size=len;returnret;}
4.类外的重载函数
ostream&operator<<(ostream&out,string&str);istream&operator>>(istream&in,string&str);booloperator>(string&str1,string&str2);booloperator>=(string&str1,string&str2);booloperator<(string&str1,string&str2);booloperator<=(string&str1,string&str2);booloperator==(string&str1,string&str2);booloperator!=(string&str1,string&str2);

流插入与流提取

ostream&operator<<(ostream&out,string&str){//out << str.c_str();for(autoch:str){out<<ch;}returnout;}istream&operator>>(istream&in,string&str){charch;inti=0;in.get(ch);//只靠in读不到' '//get全部字符都可以读charbuff[256];//它可以提高改函数的效率//如果直接把读取的数据导入str的话会开好多次空间//而预留虽然可以减少开空间的次数,但不知道初始预留多少好//因此可以栈里的buff,先把数据存它这里while(ch!='/n'||ch!=' ')//库里的读不到' '{buff[i++]=ch;in.get(ch);if(i==255){buff[i]=0;str+=buff;i=0;}}if(i>0){buff[i]=0;str+=buff;}returnin;}

关系符重载

booloperator>(string&str1,string&str2){returnstrcmp(str1.c_str(),str2.c_str())>0;}booloperator>=(string&str1,string&str2){return!(str1<str2);}booloperator<(string&str1,string&str2){returnstrcmp(str1.c_str(),str2.c_str())<0;}booloperator<=(string&str1,string&str2){return!(str1>str2);}booloperator==(string&str1,string&str2){returnstrcmp(str1.c_str(),str2.c_str())==0;}booloperator!=(string&str1,string&str2){return!(str1==str2);}

三.部分函数的改进

实现两对象交换的函数

voidswap(string&s){std::swap(_str,s._str);std::swap(_size,s._size);std::swap(_capacity,s._capacity);}

我们可以将=重载与拷贝构造的大部分工作交给swap来实现:

//构造string(string&s){//普通写法//_size = strlen(s._str);//_capacity = _size;//_str = new char[_capacity + 1];//strcpy(_str, s._str);//现代写法//用类里面的swapstringtmp(s._str);swap(tmp);//前面没写对象会默认this//这个函数结束后会自动调用tmp的析构}//=重载string&operator=(string&str){if(this!=&str){stringtmp(str._str);swap(tmp);}/return*this;}//更简单string&operator=(string str)//只传值{swap(str);return*this;}

四.补充

我实现的自定义string类可以用迭代器遍历吗?

strings("sada");for(char&ch:s){cout<<ch;}

运行起来可以发现是不能的,因为该自定义的类是没有迭代器的。但string很特殊,它储存数据的方法和数组类似,数据在空间中是连续的,因此我们可以用地址模拟实现迭代器。

typedefchar*iterator;//只有string类可以用指针模拟实现迭代器typedefconstchar*const_iterator;iteratorbegin(){return_str;}iteratorend()//返回最后一位的下一位{return_str+_size;}const_iteratorbegin()const{return_str;}const_iteratorend()const{return_str+_size;}

迭代器名和函数名必须与标准库中的一样。

完整代码

完整代码

http://www.jsqmd.com/news/537931/

相关文章:

  • Wan2.2-I2V-A14B快速上手:WebUI界面Prompt输入技巧与风格控制指南
  • 2026广州纹绣择校指南:为何艺丽是“双证”合规首选? - 梅1梅
  • Langchain原理综述
  • GanttProject完整指南:如何用免费开源工具实现专业项目管理
  • legged_control足式机器人控制框架及代码解析(五):状态估计与MPC策略融合
  • 杭州高端腕表检测服务全解析:从百达翡丽到欧米茄,京沪深杭宁锡六地检测标准与故障诊断深度报告 - 时光修表匠
  • 2026年草坪胶行业趋势报告:绿色化与专业化的未来 - 速递信息
  • Grafana 8.x实战:用ClickHouse数据打造炫酷监控仪表盘(附避坑指南)
  • 机械键盘连击问题深度解决方案:从原理到实战的全面指南
  • LightOnOCR-2-1B惊艳效果展示:复杂表格结构还原与跨语言数学公式识别
  • 杭州腕表检测|高端奢华腕表精准检测指南,六大核心城市专业维修全解析 - 时光修表匠
  • PyTorch 2.8镜像快速上手:RTX 4090D下huggingface_hub离线模型加载
  • 手把手教你配置BMI270的FIFO中断与水位线,实现低功耗数据采集(附ESP32代码)
  • 天虹购物卡回收攻略:线上方式更靠谱? - 团团收购物卡回收
  • 基于容积卡尔曼滤波的轮胎侧向力与非线性修正技术研究:MPC路径跟踪控制优化实践
  • 大润发购物卡如何回收?2026年精简指南在此 - 京回收小程序
  • 永辉超市购物卡回收技巧 - 团团收购物卡回收
  • 宴会预订流程及标准复杂?酒店哥哥满意宴会指南
  • 线上回收百联OK卡,哪些技巧能帮你省时省力? - 团团收购物卡回收
  • 免费降AI率和付费降AI率差距有多大?降论文ai率效果实测对比
  • 华为eNSP模拟器实战:5分钟搞定Telnet远程登录(附AAA认证避坑指南)
  • 页游党必看!传奇、篮球、策略全都有,点击即玩
  • 杭州高端腕表检测全解析:从百达翡丽到理查德米勒的精准评估与科学养护 - 时光修表匠
  • 探寻樱花卫厨性价比:中高端定位下的超值之选 - 速递信息
  • 降AI率工具怎么选?从降AI效果、价格、售后三维度对比推荐
  • 星露谷物语模组加载器SMAPI:5分钟快速安装与完整使用指南
  • 文本处理新利器gte-base-zh:从环境搭建到相似度计算全解析
  • 恒压供水系统:西门子224XP与昆仑TPC7062触摸屏的完美搭档
  • 如何高效获取百度网盘分享资源的提取码
  • 2026国产科学仪器崛起:太阳光模拟器采购与测评全攻略 - 品牌推荐大师