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

C++----模拟实现string

模拟实现string,首先我们要知道成员变量有哪些:

    class _string{private:char* _str;size_t capacity;//空间有多大size_t size;//有效字符多少const static size_t npos;};const size_t _string::npos=-1;//static在外面定义不需要带static,npos表示最大位置

接着写构造函数,在string中,初始化方式有无参的,有用字符串初始化的,这就要求我们写一个带缺省参数的默认构造函数:

string(const char* str=""):capacity(strlen(str)),size(capacity)
{_str=new char[capacity+1];strcpy(_str,str);
}
//为什么用"",因为它代表了\0,用它初始化再合适不过了
//为什么不用'\0'呢?因为这是一个char*,用'\0'就会用他的ASCII码值初始化
//为什么不用nullptr呢?因为在后面可能会用到_str的解引用,解引用空指针要出问题的

接下来写拷贝构造

string(const string& s)
{_str=new char[s.capacity+1];capacity=s.capacity;size=s.size;strcpy(_str,s._str);
}

赋值符号重载

//与单纯的拷贝构造不一样,复制重载原string对象一般都会有原始空间,要释放原始空间
const string& operator=(const string& s)
{//最重要的一点!一定要检查自赋值,不检查的话会导致空间释放使用未分配的空间if(this==&s)return *this;//并且释放原始空间和开辟新空间是有顺序的,开辟新空间一定要放在前面//避免开辟新空间失败导致原来空间也没有了!char *new_ptr=new char[s.size+1];strcpy(new_ptr,s._str);delete[]_str;_str=new_str;capacity = s.capacity;size = s.size;return *this; 
}

如果我们要打印string对象的字符串呢?在没有重载流提取符号的情况下:

const char* c_str() const
{return _str;
}

开始定义增删查改部分;增:有push_back、append、+=、insert,直接先定义insert,其他的都可以复用insert函数,insert有插入字符版本和字符串版本:

void reserve(size_t n)
{if(capacity<n){char* new_ptr=new char[n+1];strpy(new_ptr,_ptr);delete[]_str;_str=new_ptr;capacity=n;}
}void resize(size_t n,char ch='\0')//给一个缺省参数
{//小于size实质上就是删除多余的字符if(n<size)_str[n]='\0'else{if(n>capacity)reserve(n);for(int i=size;i<n;i++){_str[i]=ch;}_str[n]='\0';}size=n;
}//插入字符版本
string& insert(size_t pos, char ch)
{assert(pos<=size);int len=size+1;if(len>capacity)reserve(len);unsigned int end = size+1;//unsigned int end = size;//while (pos <= end)  //头插有bug,遇到unsigned<=某数要小心,容易最大化//{//	_str[end + 1] = _str[end];//	end--;//}//\0直接被处理,无需再管\0while (pos < end) //有bug,遇到unsigned<=某数要小心,容易最大化,unsigned容易减到-1成最大的{str[end] = _str[end-1];end--;}_str[pos] = ch;size += 1;return *this;
}//插入字符串版本  本质上从挪一个位置到要挪n个位置的区别
string& insert(size_t pos, const char* str)
{assert(pos<=size);int len=size+len(str);if(len>capacity)reserve(len);unsigned int end = size+len(str);//\0直接被处理,无需再管\0while (pos+len-1 < end) //有bug,遇到unsigned<=某数要小心,容易最大化,unsigned容易减到-1成最大的{str[end] = _str[end-len(str)];end--;}_str[pos] = ch;size += 1;return *this;
}

append、+=、push_back直接复用:

		string& operator+=(const char* str){insert(size,str);return *this;}string& operator+=(char ch){insert(size,ch);return *this;}void push_back(const char ch){insert(size,ch);}void append(const char* str){insert(size,ch);}

查改:

const char& operator[](int pos)const //一般情况不修改对象内容的,都用const修饰,既考虑了const对象调用,又考虑了非const调用,如果有特殊需要可以都实现,调用时会自动识别
{assert(pos<size);return *(_str+pos);
}char& operator[](int pos) //用引用返回可以直接修改
{assert(pos<size);return *(_str+pos);
}size_t find(char ch, int pos) const
{assert(pos<size);while(_str[pos]!=ch){if(pos>=size)break;pos++;}if(pos==size)return npos;elsereturn pos;
}char* find(const char* str, int pos)
{assert(pos<size);char* poss=strstr(_str+pos,str)return poss;
}const char* find(const char* str, int pos) const
{assert(pos<size);char* poss=strstr(_str+pos,str)return poss;
}

迭代器的实现

class _string
{typedef char* iterator;typedef const char* const_iterator;//string这种物理内存连续的可以这么定义指针//一定要定义const迭代器 要保证权限不会放大,以及后续一致性问题,不能const字符串的指针能修改                字符串,这就扯淡了iterator begin(){return _str;}const_iterator begin() const{return _str;}iterator end(){return _str+size;}const_iterator end() const{return _str+size;}
}//范围for就是用的迭代器,要想支持范围for遍历就必须定义迭代器begin(),end(),一个字符都不能差。

删:

void erase(size_t pos=npos, int n)
{assert(pos<size)if(pos+n>size)_str[pos]='\0';size-=n;else{int start=pos;int end=n+pos;while(start<=end){_str[start]=_str[start+n];start++;}size-=n;}}

重载流提取流插入运算符,在类外重载:

ostream& operator<<(ostream& out, const string& s)
{for(auto e: s)out<<e;return out;
}//流输入要考虑的问题就多了,要考虑效率问题,以及普通的in不处理换行符的问题。
istream& operator>>(stream& in, string& s)
{//引入内存池char tmp[128]={'\0'};ch=in.get();//可以接收换行符,空格符,如果只in>>,不会接收int i = 0;while(ch !=' ' and ch!='\n'){if(i==128)s+=tmp;i=0;memset(tmp,'\0',128);tmp[i++]=ch;ch=in.get();}s+=tmp;return in; 
}

这么写,其实有问题,输入时之前的旧内存没有释放掉:

//流输入要考虑的问题就多了,要考虑效率问题,以及普通的in不处理换行符的问题。
istream& operator>>(stream& in, string& s)
{s= string();//清空内存//引入内存池char tmp[128]={'\0'};ch=in.get();//可以接收换行符,空格符,如果只in>>,不会接收int i = 0;while(ch !=' ' and ch!='\n'){if(i==128)s+=tmp;i=0;memset(tmp,'\0',128);tmp[i++]=ch;ch=in.get();}s+=tmp;return in; 
}

相关文章:

  • 《Java编程思想》读书笔记:第十章 内部类
  • IMX675-AAQR-C 索尼图像传感器 属于索尼 Starvis 2 系列,主打 高灵敏度、低噪声,适用于工业检测、安防监控、机器视觉等场景 提供数据手册
  • 从零开始学Python游戏编程40-碰撞处理2
  • fps项目总结:生成武器子弹丧尸攻击
  • pyinstaller打包paddleocr发生错误解决
  • 【5】GD32 基础通信外设:USART、I2C、SPI
  • 正则表达式三剑客之——awk命令
  • OCR(Optical Character Recognition),光学字符识别
  • 使用 Python 项目管理工具 uv 快速创建 MCP 服务(Cherry Studio、Trae 添加 MCP 服务)
  • 通道降维方式
  • 一款好的私有云产品推荐——优刻得私有云(UCloudStack Pro)产品白皮书
  • 单机无穷大系统暂态稳定性仿真Matlab模型
  • 数据库-子查询、关联查询 和 TCL 语言
  • 智慧医疗领域TMI期刊2025年3月研究热点解析
  • 嵌入式:Linux系统应用程序(APP)启动参数及其规则详解
  • 【网络入侵检测】基于源码分析Suricata的PCAP模式
  • 计算器(WEB)
  • 流动式起重机Q2证考试有哪些科目?
  • C++与Python编写二进制转十进制
  • 机器人行业研究系列报告
  • 财政部、证监会:加强对会计师事务所从事证券服务业务的全流程监管
  • 在黄岩朵云书院,邂逅陈丹燕与月季花的故事
  • 双拥主题歌曲MV:爱我人民,爱我军
  • 上海银行一季度净赚逾62亿增2.3%,不良贷款率与上年末持平
  • 山西省援疆前方指挥部总指挥刘鹓已任忻州市委副书记
  • 梁启超“失肾记”的余波:中西医论战与最后的真相