【c++篇】:模拟实现string类--探索字符串操纵的底层逻辑

[复制链接]
发表于 2026-1-2 11:41:27 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
✨感谢您阅读本篇文章,文章内容是个人学习条记的整理,如果那里有误的话还请您指正噢✨
✨ 个人主页:余辉zmh–CSDN博客
✨文章所属专栏:c++篇–CSDN博客
  



媒介

在上一篇文章中,我们相识到了std::string类的常用接口函数以及怎样纯熟使用。在这片文章中,我们将深入探究怎样模拟实现一个根本的string类。我们的目的不是创建一个功能完备的string库,而是通过这个过程来学习字符串处理惩罚的根本原理和常见的实现本事。通过模拟实现string类,我们不但可以或许深入明确字符串的内部工作原理,还能锻炼我们的编程本事,进步办理题目的本事,盼望这篇文章能过为你的编程之旅提供有代价的参考和开导。
   留意:模拟实现string类必要用到三个文件
  

  • test.cpp文件用来举行测试
  • string.cpp文件用来界说接口函数(部分较为短小的函数将会直接在string.h文件中界说)
  • string.h文件用来声明头文件和string类
  一.string类的默认成员函数以及深拷贝

1.根本框架

为了和库内里的std::string类举行区分,我们起首界说一个定名空间Mystring用来封装我们本身模拟实现的string类。
根本框架如下:
  1. namespace Mystring{
  2.     class string{
  3.     Public:
  4.         static const size_t npos=-1;
  5.         //成员函数
  6.         
  7.     private:
  8.         //成员变量
  9.         char* _str;
  10.         size_t _size;
  11.         size_t capacity;
  12.     };
  13. }
复制代码


  • _str在堆上开发动态内存用来存储string对象的数据。
  • _size用来纪录string对象的实际巨细。
  • _capacity用来纪录当前string对象可存储的最大容量。
  • npos是一个无符号整形的最大值,在查找等干系函数会用到。
2.默认成员函数

前面我们知道,一个类中有六个默认成员函数(在我之前的文章类和对象(二)中有关于默认成员函数的具体解说,不清晰的可以看我之前的文章),在模拟实现string类时,我们只必要实现常用的四个(构造函数,析构函数,拷贝构造函数,赋值运算符重载)即可。
1.构造函数



  • 代码实现:
    1. //string.h中声明
    2. string(const char* str = "");
    3. //string.cpp中定义
    4. Mystring::string::string(const char* str)
    5. :_size(strlen(str))
    6. ,_capacity(_size)
    7. ,_str(new char[_size+1])
    8. {
    9.     memcpy(_str,str,_size+1);
    10. }
    复制代码
  • 实现原理:

    • str字符串作为常量参数用来创建string对象,缺省值为空字符串(当没有参数时就是创建一个空对象),缺省值要在声明中给,不能再界说中给。
    • _size字符串巨细和_capacity容量初始化值为参数str字符串的巨细(strlen(str))。
    • _str指针用来指向存储string对象的动态内存,开发空间的巨细为参数str字符串的巨细加一,加一是为了存放末了的’\0’,开发空间后要将str字符串内容拷贝到开发的动态内存。

2.析构函数



  • 代码实现:
    1. //string.h文件中声明
    2. ~string();
    3. //string.cpp文件中定义
    4. Mystring::string::~string()
    5. {
    6.     delete[] _str;
    7.     _str=nullptr;
    8.     _size=0;
    9.     _capacity=0;
    10. }
    复制代码
  • 实现原理:

    • 开释动态内存空间,再将_str指针置为空指针。
    • _size字符串巨细和_capacity容量置为0。

3.拷贝构造函数(深拷贝)



  • 代码实现:
    1. //string.h文件中声明
    2. string(const string&s);
    3. //string.cpp文件中定义
    4. Mystring::string::string(const string&s)
    5. {
    6.     _str=new char[s._capacity+1];
    7.     strcpy(_str,s._str);
    8.     _size=s._size;
    9.     _capacity=s._capacity;
    10. }
    复制代码
  • 实现原理:

    • 用一个string对象拷贝构造一个新的string对象,拷贝构造函数必要完成深拷贝。
    • 先用字符串s的容量作为新空间的巨细申请一个新的动态内存空间,再将s字符串的数据拷贝到新的内存空间中。
    • 新的string对象的_size和_capacity分别是原string对象的_size和_capacity.

4.赋值运算符重载(深拷贝)



  • 代码实现:
    1. //string.h文件中声明
    2. string& operator=(const string&s);
    3. //string.cpp文件中定义
    4. Mystring::string& Mystring::string::operator=(const string&s)
    5. {
    6.     char* tmp=new char[s._capacity+1];
    7.     memcpy(tmp,s._str,s._size+1);
    8.     delete[] _str;
    9.     _str=tmp;
    10.     _capacity=s._capacity;
    11.     _size=s._size;
    12.     return *this;
    13. }
    复制代码
  • 实现原理:

    • 赋值和拷贝构造的差别点在于,拷贝构造是用已有的对象拷贝构造一个新的对象;而赋值是用一个已存在的对象赋值给另一个已存在的对象,赋值也是必要完成深拷贝。
    • 先用赋值对象s的容量巨细申请一个新的动态内存空间,设置一个新的tmp指针先指向这块空间,再将赋值对象s的数据拷贝到新的内存空间中。
    • 开释被赋值对象的原有空间,再将被赋值对象的_str指针指向新的内存空间。
    • 被赋值对象的_size和_capacity分别是赋值对象s的_size和_capacity.

3.什么是深拷贝

深拷贝(Deep Copy)是对象复制操纵中的一种,它不但仅复制对象的表层数据(如指针或引用),还会递归地复制对象内部全部动态分配的内存、引用的其他对象或其他资源。如许,复制出来的新对象与原始对象在内存中是完全独立的,对它们的修改不会影响到相互。
深拷贝的须要性

当对象包罗指向动态分配内存的指针或其他必要管理的资源时,浅拷贝(仅复制指针值)会导致两个对象共享同一块内存。这大概会引发以下题目:
   

  • 数据破坏:一个对象修改了它共享的内存中的数据,导致另一个对象看到的数据也发生了变革。
  • 内存走漏:如果两个对象都以为本身拥有这块内存,并在析构时实行开释它,就会导致重复开释内存的错误(double free),进而大概导致步调瓦解。
  • 资源管理杂乱:如果对象还管理其他资源(如文件句柄、网络毗连等),共享这些资源大概会导致资源被不测关闭或重复访问。
  深拷贝的实现

实现深拷贝通常涉及以下几个步调:
   

  • 为新对象分配内存:如果原始对象包罗动态分配的内存,深拷贝的第一步是为新对象分配相应的内存空间。
  • 复制数据:将原始对象中的数据复制到新分配的内存中。如果数据本身也是对象(即对象包罗指向其他对象的指针),则必要递归地应用深拷贝。
  • 更新指针:将新对象的指针成员指向新分配的内存,而不是原始对象的内存。
  • 处理惩罚其他资源:如果对象管理其他资源(如文件、网络毗连等),则必要确保新对象也能精确地获取或创建这些资源的副本。
  4.测试

测试代码如下:
  1. void test1(){
  2.     //创建s1对象
  3.     Mystring::string s1("hello world");
  4.     //用s1对象拷贝构造s2对象
  5.     Mystring::string s2(s1);
  6.     //将s1对象赋值给s3对象
  7.     Mystring::string s3("hello");
  8.     s3=s1;
  9. }
复制代码
测试效果如下:

二.string类的访问和迭代器干系函数

1.访问干系函数



  • at()函数代码实现:
    1. //string文件中声明和定义
    2. char& at(size_t pos)
    3. {
    4.     //断言检查pos是否符合字符串的范围
    5.     assert(pos<_size);
    6.     //直接返回字符数组对应下标上的字符即可
    7.     return _str[pos];
    8. }
    复制代码
  • operator[]函数代码实现:
    1. //string文件中声明和定义
    2. //和at()函数同理
    3. char& operator[](size_t pos)
    4. {
    5.     assert(pos<_size);
    6.     return _str[pos];
    7. }
    复制代码
2.迭代器干系函数

1.平常string对象的迭代器



  • 范例界说:
    1. //普通string对象的迭代器类型
    2. typedef char* iterator;
    复制代码
  • begin()函数代码实现:
    1. //string文件中声明和定义
    2. iterator begin()const
    3. {
    4.     //返回_str首元素的地址
    5.      return _str;
    6. }
    复制代码
  • end()函数代码实现:
    1. //string文件中声明和定义
    2. iterator end()const
    3. {
    4.     //返回_str最后一个元素的下一个位置的地址
    5.     return _str+_size;
    6. }
    复制代码
2.const string对象的迭代器



  • 范例界说:
    1. //const string对象的迭代器类型
    2. typedef const char* const_iterator;
    复制代码
  • cbegin()函数代码实现:
    1. //string文件中声明和定义
    2. const_iterator begin()const
    3. {
    4.     //返回_str首元素的地址
    5.      return _str;
    6. }
    复制代码
  • cend()函数代码实现:
    1. //string文件中声明和定义
    2. const_iterator end()const
    3. {
    4.     //返回_str最后一个元素的下一个位置的地址
    5.     return _str+_size;
    6. }
    复制代码
3.测试

测试代码如下:
  1. void test2(){
  2.     Mystring::string s1("hello world");
  3.     //使用opreator[]打印s1
  4.     for(size_t i=0;i<s1.size();i++){
  5.         cout<<s1[i]<<" ";
  6.     }
  7.     cout<<endl;
  8.     //使用普通对象的迭代器打印s1
  9.     Mystring::string::iterator it=s1.begin();
  10.     while(it!=s1.end()){
  11.         cout<<*it<<" ";
  12.         it++;
  13.     }
  14.     cout<<endl;
  15.     //使用const对象的迭代器打印s2
  16.     const Mystring::string s2("hello");
  17.     Mystring::string::const_iterator rit=s2.begin();
  18.     while(rit!=s2.end()){
  19.         cout<<*rit<<" ";
  20.         rit++;
  21.     }
  22.     cout<<endl;
  23. }
复制代码
测试效果如下:

三.string类的容量干系函数

1.容量巨细干系函数

获取string对象的巨细必要使用size()函数,获取容量则必要使用capacity()函数


  • size()函数代码实现:
    1. //string.h文件中声明和定义
    2. //直接返回_size即可
    3. size_t size()
    4. {
    5.     return _size;
    6. }
    复制代码
  • capacity()函数代码实现:
    1. //string.h文件中声明和定义
    2. //直接返回_capacity即可
    3. size_t capacity()
    4. {
    5.     return _capacity;
    6. }        
    复制代码
2.扩容干系函数

string类扩容干系的函数紧张是reserve()和resize()。


  • reserve()函数代码实现:
    1. //string.h文件中声明
    2. void reserve(size_t);
    3. //string.cpp文件中定义
    4. void Mystring::string::reserve(size_t n)
    5. {
    6.     if(n>_capacity){
    7.         char*tmp=new char[n+1];
    8.         memcpy(tmp,_str,_size+1);
    9.         delete[] _str;
    10.         _str=tmp;
    11.         _capacity=n;
    12.     }
    13. }
    复制代码
  • 实现原理:

    • 起首判定必要扩容的巨细n是否大于原容量巨细_capacity,如果小于则不举行扩容,大于时就必要扩容。
    • 扩容时先开发内存巨细为(n+1)的动态内存空间,在设置一个新的字符指针tmp指向新的内存空间,然后将原string对象的数据拷贝到新的内存空间中。
    • 开释原string对象的_str指针,再重新指向开发的新内存空间,末了更改内存巨细为n。

  • resize()函数代码实现:
    1. //string.h文件中声明
    2. void resize(size_t n,char ch='\0');
    3. //string.cpp文件中定义
    4. void Mystring::string::resize(size_t n,char ch)
    5. {
    6.     if(n>_capacity){
    7.         reserve(n);
    8.     }
    9.     if(n>_size){
    10.         for(size_t i=_size;i<n;i++){
    11.             _str[i]=ch;
    12.         }
    13.     }
    14.     _size=n;
    15.     _str[_size]='\0';
    16. }
    复制代码
  • 实现原理:

    • 起首依然是必要判定扩容的巨细n是否大于原容量巨细_capacity,和reserve()函数差别的是,resize对于扩容巨细n小于原容量巨细时会发生截断,大于时就会举行扩容操纵,这里扩容操纵直接调用reserve()函数即可。
    • 如果扩容巨细n大于原string对象的_size,必要将多余的空间初始化为参数ch,参数ch的缺省值设置为’\0’(要在声明中给),没有传参时,默认初始化为0。

3.测试

测试代码如下:
  1. void test3(){
  2.     Mystring::string s1("hello world");
  3.     cout<<s1.size()<<" "<<s1.capacity()<<endl;
  4.     //s1容量扩为15
  5.     s1.reserve(15);
  6.     cout<<s1.size()<<" "<<s1.capacity()<<endl;
  7.     //s1容量扩为20,多余空间用字符a填充
  8.     s1.resize(20,'a');
  9.     cout<<s1.size()<<" "<<s1.capacity()<<endl;
  10.     cout<<s1<<endl;
  11.     //s1缩容为8,发生截断
  12.     s1.resize(8);
  13.     cout<<s1.size()<<" "<<s1.capacity()<<endl;
  14.     cout<<s1<<endl;
  15. }
复制代码
测设效果如下:

四.string类的修改干系函数

1.拼接操纵干系函数



  • 1.push_back()函数实现:
    1. //string.h文件中声明
    2. void push_back(char ch);
    3. //string.cpp文件中定义
    4. void Mystring::string::push_back(char ch)
    5. {
    6.     if(_size==_capacity){
    7.         reserve(_capacity==0?4:2*_capacity);
    8.     }
    9.     _str[_size]=ch;
    10.     _size++;
    11.     _str[_size]='\0';
    12. }
    复制代码
    2.实现原理:

    • push_back()函数的功能是尾插单个字符,在尾插之前要先判定是否必要扩容,在扩容时,如果必要尾插的string对象是空对象扩容 巨细先设置为4,如果不是空对象则扩容巨细是原容量的二倍,扩容直接调用reserve()函数即可。
    • 插入时,将原来字符串的’\0’位置存放插入的字符ch,再将巨细_size增长一,末了重新在字符串的末了加上’\0’。

  • 1.append()函数实现:
    append()函数有两种差别的实现,一个是在原string对象后增长单个字符,一个是增长字符串。
    1. //string.h文件中声明
    2. void append(char ch);               
    3. void append(const char* str);  
    4. //string.cpp文件中定义
    5. //增加单个字符
    6. void Mystring::string::append(char ch)
    7. {
    8.     push_back(ch);
    9. }
    10. //增加字符串
    11. void Mystring::string::append(const char* str)
    12. {
    13.     size_t len=strlen(str);
    14.     if(_size+len>_capacity){
    15.         reserve(_size+len);
    16.     }
    17.     //_str加上_size就是原字符串结尾的位置,插入的字符串拷贝到原字符串后面
    18.     memcpy(_str+_size,str,len+1);
    19.     _size+=len;
    20. }
    复制代码
    2.实现原理:

    • 增长单个字符直接调用push_back函数。
    • 增长字符串时,先获取插入字符串的巨细len,然后判定原字符串的巨细加上插入字符串的巨细是否大于容量_capacity,如果大于必要先举行扩容,扩容巨细为原字符串的巨细加上插入字符串的巨细。
    • 将插入的字符串拷贝到原字符串反面,拷贝巨细为len+1,然后修改_size值。

  • 1.operator+=函数实现:
    operator+=函数和append()函数一样有两种差别的实现,在原string对象后增长单个字符和字符串。
    1. //string.h文件中声明
    2. string& operator+=(char ch);         
    3. string& operator+=(const char* str);
    4. //string.cpp文件中定义
    5. //增加单个字符
    6. Mystring::string& Mystring::string::operator+=(char ch)
    7. {
    8.     push_back(ch);
    9.     return *this;
    10. }
    11. //增加字符串
    12. Mystring::string& Mystring::string::operator+=(const char* str)
    13. {
    14.    append(str);
    15.     return *this;
    16. }
    复制代码
    2.实现原理:

    • 增长单个字符直接调用push_back()函数,末了要返回this指针。
    • 增长字符串直接调用append(const char* str)函数,末了返回this指针。

2.插入操纵干系函数



  • insert()函数实现:
    1.插入n个字符:
    1. //string.h文件中声明
    2. void insert(size_t pos,size_t n,char ch);
    3. //string.cpp文件中定义
    4. void Mystring::string::insert(size_t pos,size_t n,char ch)
    5. {
    6.     assert(pos<_size);
    7.     if((_size+n)>_capacity){
    8.         reserve(_size+n);
    9.     }
    10.     size_t end=_size;
    11.     while(end>=pos&&end!=npos){
    12.         _str[end+n]=_str[end];
    13.         end--;
    14.     }
    15.     for(size_t i=0;i<n;i++){
    16.         _str[pos+i]=ch;
    17.     }
    18.     _size+=n;
    19. }
    复制代码
    实现原理:

    • 如果原字符串巨细加上插入的个数大于容量巨细时,必要先举行扩容,扩容巨细为原字符串巨细加上插入的个数。
    • 将插入位置反面的数据依次今后移动n个位置。
    • 再将移动后空出来的位置插入n个字符ch。末了修改_size巨细。
    2.插入字符串:
    1. //string.h文件中声明
    2. void insert(size_t pos,const char*str);
    3. //string.cpp文件中定义
    4. void Mystring::string::insert(size_t pos,const char*str)
    5. {
    6.     assert(pos<_size);
    7.     size_t len=strlen(str);
    8.     if(_size+len>_capacity){
    9.         reserve(_size+len);
    10.     }
    11.     size_t end=_size;
    12.     while(end>=pos&&end!=npos){
    13.         _str[end+len]=_str[end];
    14.         end--;
    15.     }
    16.     for(size_t i=0;i<len;i++){
    17.         _str[pos+i]=str[i];
    18.     }
    19.     _size+=len;
    20. }
    复制代码
    实现原理:
       

    • 插入字符串和插入n个字符原理类似,差别点是,末了插入时,必要依次插入字符串的字符。

3.删除操纵干系函数



  • erase()函数实现:
    1. //string.h中声明
    2. void erase(size_t pos,size_t len=npos);
    3. //string.cpp文件中定义
    4. void Mystring::string::erase(size_t pos,size_t len)
    5. {
    6.     assert(pos<_size);
    7.     if(len==npos||pos+len>=_size){
    8.         _size=pos;
    9.         _str[_size]='\0';
    10.     }
    11.     else{
    12.         size_t end=len+pos;
    13.         while(end<=_size){
    14.             _str[pos++]=_str[end++];
    15.         }
    16.         _size-=len;
    17.     }
    18. }
    复制代码
  • 实现原理:

    • 删除要分为两种情况,第一种,如果删除的个数大于_size大概len即是npos值,直接从pos位置将反面全部删除。
    • 第二种,依次将反面的字符往前移动,从而到达删除的目的。

4.测试

测试代码如下:
  1. void test4(){
  2.     //创建一个空对象s1
  3.     Mystring::string s1;
  4.     //s1追加字符串hello
  5.     s1.append("hello");
  6.     cout<<s1<<endl;
  7.     //s1追加字符串world
  8.     s1+="world";
  9.     cout<<s1<<endl;
  10.     //s1尾插字符!
  11.     s1.push_back('!');
  12.     cout<<s1<<endl;
  13.     //在s1下标为6的位置插入***
  14.     s1.insert(6,"***");
  15.     cout<<s1<<endl;
  16.     //删除s1下标为10后面的所有字符
  17.     s1.erase(10);
  18.     cout<<s1<<endl;
  19.     //删除s1下标为5后面的三个字符
  20.     s1.erase(5,3);
  21.     cout<<s1<<endl;
  22. }
复制代码
测试效果如下:

五.string类的流插入和流提取函数



  • 1.operator<<流插入函数实现:
    1. //string.h文件中声明
    2. ostream& operator<<(ostream& out,const string&s);
    3. //string.cpp文件中定义
    4. ostream& Mystring::operator<<(ostream& out,const string&s)
    5. {
    6.     cout<<"operator<<"<<endl;
    7.     for(auto e:s){
    8.         out<<e;
    9.     }
    10.     return out;
    11. }
    复制代码
  • 1.operator>>流提取函数实现:
    1. //string.h文件中声明
    2. istream& operator>>(istream &in,string &s);
    3. //string.cpp文件中定义
    4. istream& Mystring::operator>>(istream &in, string &s)
    5. {
    6.     cout<<"operator>>"<<endl;
    7.     s.clear();
    8.     char ch = in.get();
    9.         // 处理前缓冲区前面的空格或者换行
    10.         while (ch == ' ' || ch == '\n')
    11.         {
    12.                 ch = in.get();
    13.         }
    14.         char buff[128];
    15.         int i = 0;
    16.         while (ch != ' ' && ch != '\n')
    17.         {
    18.                 buff[i++] = ch;
    19.                 if (i == 127)
    20.                 {
    21.                         buff[i] = '\0';
    22.                         s += buff;
    23.                         i = 0;
    24.                 }
    25.                 ch = in.get();
    26.         }
    27.         if (i != 0)
    28.         {
    29.                 buff[i] = '\0';
    30.                 s += buff;
    31.         }
    32.         return in;
    33. }
    复制代码
测试代码如下:
  1. void test5(){
  2.     Mystring::string s1;
  3.     //输入
  4.     cin>>s1;
  5.     //输出
  6.     cout<<s1<<endl;
  7. }
复制代码

六.string类完备代码

1.string.h头文件代码

  1. #include<iostream>
  2. #include<string>
  3. #include<string.h>
  4. #include<assert.h>
  5. using namespace std;
  6. namespace Mystring{
  7.     class string{
  8.     public:
  9.         static const size_t npos=-1;
  10.         //构造函数
  11.         string(const char* str = "");
  12.         //析构函数
  13.         ~string();
  14.         //拷贝构造函数
  15.         string(const string&s);
  16.         //赋值运算符重载
  17.         string& operator=(const string&s);
  18.         
  19.         //c格式打印
  20.         const char* c_str(){
  21.             return _str;
  22.         }
  23.         //容量大小
  24.         size_t size()
  25.         {
  26.             return _size;
  27.         }
  28.         size_t capacity()
  29.         {
  30.             return _capacity;
  31.         }
  32.         //扩容
  33.         void reserve(size_t n);
  34.         void resize(size_t n,char ch='\0');
  35.         void clear(){
  36.             _size=0;
  37.             _str[_size]='\0';
  38.         }
  39.         //访问方式
  40.         char& operator[](size_t pos){
  41.             assert(pos<_size);
  42.             return _str[pos];
  43.         }
  44.         char& at(size_t pos){
  45.             assert(pos<_size);
  46.             return _str[pos];
  47.         }
  48.         //迭代器
  49.         typedef char* iterator;
  50.         iterator begin() {
  51.             return _str;
  52.         }
  53.         iterator end() {
  54.             return _str+_size;
  55.         }
  56.         typedef const char* const_iterator;
  57.         const_iterator begin()const {
  58.             return _str;
  59.         }
  60.         const_iterator end()const {
  61.             return _str+_size;
  62.         }
  63.         //修改
  64.         void push_back(char ch);            
  65.         void append(char ch);               
  66.         void append(const char* str);        
  67.         string& operator+=(char ch);         
  68.         string& operator+=(const char* str);
  69.         void insert(size_t pos,size_t n,char ch);
  70.         void insert(size_t pos,const char*str);
  71.         void erase(size_t pos,size_t len=npos);
  72.         //查找
  73.         size_t find(char ch,size_t pos=0);
  74.         size_t find(const char*str,size_t pos=0);
  75.         //友元函数
  76.         friend ostream& operator<<(ostream& out,const string&s);
  77.         friend istream& operator>>(istream& in,string&s);
  78.     private:
  79.         int _size;
  80.         int _capacity;
  81.         char* _str;
  82.     };
  83.     //非string成员函数
  84.     ostream& operator<<(ostream& out,const string&s);
  85.     istream& operator>>(istream& in,string&s);
  86. }
复制代码
2.string.cpp函数界说文件代码

  1. #include"string.h"
  2. Mystring::string::string(const char* str)
  3. :_size(strlen(str))
  4. ,_capacity(_size)
  5. ,_str(new char[_size+1])
  6. {
  7.     cout<<"string()"<<endl;
  8.     memcpy(_str,str,_size+1);
  9. }
  10. Mystring::string& Mystring::string::operator=(const string&s)
  11. {
  12.     cout<<"operator="<<endl;
  13.     char* tmp=new char[s._capacity+1];
  14.     memcpy(tmp,s._str,s._size+1);
  15.     delete[] _str;
  16.     _str=tmp;
  17.     _capacity=s._capacity;
  18.     _size=s._size;
  19.     return *this;
  20. }
  21. Mystring::string::~string()
  22. {
  23.     cout<<"~string()"<<endl;
  24.     delete[] _str;
  25.     _str=nullptr;
  26.     _size=0;
  27.     _capacity=0;
  28. }
  29. Mystring::string::string(const string&s)
  30. {
  31.     cout<<"string()"<<endl;
  32.     _str=new char[s._capacity+1];
  33.     strcpy(_str,s._str);
  34.     _size=s._size;
  35.     _capacity=s._capacity;
  36. }
  37. void Mystring::string::reserve(size_t n)
  38. {
  39.     if(n>_capacity){
  40.         char*tmp=new char[n+1];
  41.         memcpy(tmp,_str,_size+1);
  42.         delete[] _str;
  43.         _str=tmp;
  44.         _capacity=n;
  45.     }
  46. }
  47. void Mystring::string::resize(size_t n,char ch)
  48. {
  49.     if(n>_capacity){
  50.         reserve(n);
  51.     }
  52.     if(n>_size){
  53.         for(size_t i=_size;i<n;i++){
  54.             _str[i]=ch;
  55.         }
  56.     }
  57.     _size=n;
  58.     _str[_size]='\0';
  59. }
  60. void Mystring::string::push_back(char ch)
  61. {
  62.     if(_size==_capacity){
  63.         reserve(_capacity==0?4:2*_capacity);
  64.     }
  65.     _str[_size]=ch;
  66.     _size++;
  67.     _str[_size]='\0';
  68. }
  69. void Mystring::string::append(char ch)
  70. {
  71.     push_back(ch);
  72. }
  73. void Mystring::string::append(const char* str)
  74. {
  75.     size_t len=strlen(str);
  76.     if(_size+len>_capacity){
  77.         reserve(_size+len);
  78.     }
  79.     memcpy(_str+_size,str,len+1);
  80.     _size+=len;
  81. }
  82. Mystring::string& Mystring::string::operator+=(char ch)
  83. {
  84.     push_back(ch);
  85.     return *this;
  86. }
  87. Mystring::string& Mystring::string::operator+=(const char* str)
  88. {
  89.    append(str);
  90.     return *this;
  91. }
  92. size_t Mystring::string::find(char ch,size_t pos)
  93. {
  94.     assert(pos<_size);
  95.     for(size_t i=pos;i<_size;i++){
  96.         if(_str[i]==ch){
  97.             return i;
  98.         }
  99.     }
  100.     return npos;
  101. }
  102. size_t Mystring::string::find(const char*str,size_t pos)
  103. {
  104.     assert(pos<_size);
  105.     const char* ptr=strstr(_str+pos,str);
  106.     if(ptr){
  107.         return ptr-_str;
  108.     }
  109.     else{
  110.         return npos;
  111.     }
  112. }
  113. void Mystring::string::insert(size_t pos,size_t n,char ch)
  114. {
  115.     assert(pos<_size);
  116.     if((_size+n)>_capacity){
  117.         reserve(_size+n);
  118.     }
  119.     size_t end=_size;
  120.     while(end>=pos&&end!=npos){
  121.         _str[end+n]=_str[end];
  122.         end--;
  123.     }
  124.     for(size_t i=0;i<n;i++){
  125.         _str[pos+i]=ch;
  126.     }
  127.     _size+=n;
  128. }
  129. void Mystring::string::insert(size_t pos,const char*str)
  130. {
  131.     assert(pos<_size);
  132.     size_t len=strlen(str);
  133.     if(_size+len>_capacity){
  134.         reserve(_size+len);
  135.     }
  136.     size_t end=_size;
  137.     while(end>=pos&&end!=npos){
  138.         _str[end+len]=_str[end];
  139.         end--;
  140.     }
  141.     for(size_t i=0;i<len;i++){
  142.         _str[pos+i]=str[i];
  143.     }
  144.     _size+=len;
  145. }
  146. void Mystring::string::erase(size_t pos,size_t len)
  147. {
  148.     assert(pos<_size);
  149.     if(len==npos||pos+len>=_size){
  150.         _size=pos;
  151.         _str[_size]='\0';
  152.     }
  153.     else{
  154.         size_t end=len+pos;
  155.         while(end<=_size){
  156.             _str[pos++]=_str[end++];
  157.         }
  158.         _size-=len;
  159.     }
  160. }
  161. ostream& Mystring::operator<<(ostream& out,const string&s)
  162. {
  163.     //cout<<"operator<<"<<endl;
  164.     for(auto e:s){
  165.         out<<e;
  166.     }
  167.     return out;
  168. }
  169. istream& Mystring::operator>>(istream &in, string &s)
  170. {
  171.     cout<<"operator>>"<<endl;
  172.     s.clear();
  173.     char ch = in.get();
  174.         // 处理前缓冲区前面的空格或者换行
  175.         while (ch == ' ' || ch == '\n')
  176.         {
  177.                 ch = in.get();
  178.         }
  179.         char buff[128];
  180.         int i = 0;
  181.         while (ch != ' ' && ch != '\n')
  182.         {
  183.                 buff[i++] = ch;
  184.                 if (i == 127)
  185.                 {
  186.                         buff[i] = '\0';
  187.                         s += buff;
  188.                         i = 0;
  189.                 }
  190.                 ch = in.get();
  191.         }
  192.         if (i != 0)
  193.         {
  194.                 buff[i] = '\0';
  195.                 s += buff;
  196.         }
  197.         return in;
  198. }
复制代码
3.test.cpp测试文件代码

  1. #include"string.h"void test1(){
  2.     //创建s1对象
  3.     Mystring::string s1("hello world");
  4.     //用s1对象拷贝构造s2对象
  5.     Mystring::string s2(s1);
  6.     //将s1对象赋值给s3对象
  7.     Mystring::string s3("hello");
  8.     s3=s1;
  9. }
  10. void test2(){
  11.     Mystring::string s1("hello world");
  12.     //使用opreator[]打印s1
  13.     for(size_t i=0;i<s1.size();i++){
  14.         cout<<s1[i]<<" ";
  15.     }
  16.     cout<<endl;
  17.     //使用普通对象的迭代器打印s1
  18.     Mystring::string::iterator it=s1.begin();
  19.     while(it!=s1.end()){
  20.         cout<<*it<<" ";
  21.         it++;
  22.     }
  23.     cout<<endl;
  24.     //使用const对象的迭代器打印s2
  25.     const Mystring::string s2("hello");
  26.     Mystring::string::const_iterator rit=s2.begin();
  27.     while(rit!=s2.end()){
  28.         cout<<*rit<<" ";
  29.         rit++;
  30.     }
  31.     cout<<endl;
  32. }
  33. void test3(){
  34.     Mystring::string s1("hello world");
  35.     cout<<s1.size()<<" "<<s1.capacity()<<endl;
  36.     //s1容量扩为15
  37.     s1.reserve(15);
  38.     cout<<s1.size()<<" "<<s1.capacity()<<endl;
  39.     //s1容量扩为20,多余空间用字符a填充
  40.     s1.resize(20,'a');
  41.     cout<<s1.size()<<" "<<s1.capacity()<<endl;
  42.     cout<<s1<<endl;
  43.     //s1缩容为8,发生截断
  44.     s1.resize(8);
  45.     cout<<s1.size()<<" "<<s1.capacity()<<endl;
  46.     cout<<s1<<endl;
  47. }
  48. void test4(){
  49.     //创建一个空对象s1
  50.     Mystring::string s1;
  51.     //s1追加字符串hello
  52.     s1.append("hello");
  53.     cout<<s1<<endl;
  54.     //s1追加字符串world
  55.     s1+="world";
  56.     cout<<s1<<endl;
  57.     //s1尾插字符!
  58.     s1.push_back('!');
  59.     cout<<s1<<endl;
  60.     //在s1下标为6的位置插入***
  61.     s1.insert(6,"***");
  62.     cout<<s1<<endl;
  63.     //删除s1下标为10后面的所有字符
  64.     s1.erase(10);
  65.     cout<<s1<<endl;
  66.     //删除s1下标为5后面的三个字符
  67.     s1.erase(5,3);
  68.     cout<<s1<<endl;
  69. }
  70. void test5(){
  71.     Mystring::string s1;
  72.     //输入
  73.     cin>>s1;
  74.     //输出
  75.     cout<<s1<<endl;
  76. }
  77. int main(){   //test1();   //test2();   //test3();   //test4();   test5();   return 0;}
复制代码
以上就是关于怎样模拟实现string类的解说,如果那里有错的话,可以在批评区指正,也接待各人一起讨论学习,如果对你的学习有资助的话,点点赞关注支持一下吧!!!

回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表