(C++ STL)string类的简单模拟实现与源码展示

[复制链接]
发表于 2026-1-31 09:46:32 | 显示全部楼层 |阅读模式

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

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

×
一、前言

C++ 为了更安全、简单的使用字符串,对 C语言 中的字符串和相干函数举行封装,实现了 string 类。接下来将会实现 string 与一部门常用的函数。
参考:legacy.cplusplus.com网站的 string
具体实现:

  • string部门构造函数、析构函数、赋值运算符重载。
  • Iterator 中的 begin、end。
  • Capacity 中的 size、resize、capacity、reserve、clear、empty。
  • Element access 中的 operator[]。
  • Modifiers 中的 operator+=、append、push_back、insert、erase、swap、pop_back 。
  • String operations 中的 c_str、find。
  • Non-member function overload 中的 relational operators、operator>>、operator<<。
二、string 的成员变量

在 string.h 中:
  1. namespace my
  2. {
  3.         class string
  4.         {
  5.         public:
  6.                 static const size_t npos = -1;
  7.         private:
  8.                 char* _str;
  9.                 size_t _capacity;
  10.                 size_t _size;
  11.         };
  12. }
复制代码

  • npos 体现的是 string 的竣事位子,具体可参考:C++中string::npos的一些用法总结
  • _str 字符指针用来存储 在堆上开辟的 字符串数据的 地点。
  • _capacity 体现容器空间巨细,由于 C语言 字符串末端隐蔽了一个 ’ \0 ',则真实存储字符的容量为 _capacity - 1。
  • _size 体现当前字符串巨细(不含 ’ \0 ')。
三、string 的紧张部门实现

思量到代码复用,实现并不按照上述分列次序,且只罗列一部门紧张的功能。
reserve

参考:std::string::reserve
C++ 对 string reserve函数规定:

  • 当 原空间巨细 小于 需求巨细 时, 对原空间扩容到需求巨细或其以上。
  • 当 原空间 大于或便是 需求 时,非须要的缩减空间调解。
这里实现的空间增长为严格的 2 倍扩容,对于 序号 2 的情况接纳直接忽视。
在 string.cpp 中:
  1. void my::string::reserve(size_t n)
  2. {
  3.         if (n + 1 <= _capacity)                        // 考虑末尾 '\0'
  4.         {
  5.                 return;
  6.         }
  7.         size_t newCapacity = _capacity == 0 ? MY_STRING_INIT_CAPACITY : _capacity * 2;
  8.         // n 仍然大于newCapacity时继续扩容
  9.         // newCapacity <= n 等价 newCapacity < n + 1
  10.         while (newCapacity <= n)       
  11.         {
  12.                 newCapacity <<= 1;
  13.         }
  14.         char* str1 = nullptr;                        // str1存储原空间地址       
  15.         std::swap(str1, _str);       
  16.         _str = new char[newCapacity];        // _str 新开空间后拷贝
  17.         // _size >= _capacity 只出现在初始化时(这时 _size == _capacity == 0)
  18.         // 以防止超出 _capacity 的非法内存访问
  19.         memcpy(_str, str1, sizeof(char) * (_size >= _capacity ? _capacity : _size + 1));
  20.         _capacity = newCapacity;
  21.         delete[] str1;
  22. }
复制代码
Iterator

这里迭代器只对原生 char* 举行封装。
参考:std::string::begin
参考:std::string::end
这里只实现部门。
在 my::string 中:
  1.         typedef char* iterator;
  2.                 iterator begin()
  3.         {
  4.             return _str;
  5.         }
  6.         iterator end()
  7.         {
  8.             return _str + _size;
  9.         }
复制代码
operator[]

参考:std::string:perator[]
在 my::string 类中
  1.         char& operator[](size_t index)
  2.         {
  3.             return *(_str + index);
  4.         }
  5.         const char& operator[](size_t index) const
  6.         {
  7.             return *(_str + index);
  8.         }
复制代码
insert

这里只实现两个。
参考:std::string::insert
在 string.cpp 中:
  1. // 在 pos 位置上插入 字符ch / 字符串str,并返回该string
  2. my::string& my::string::insert(size_t pos, char ch)
  3. {
  4.         assert(pos <= _size);
  5.         reserve(++_size);
  6.         // 将 pos 原位置与之后字符向后移动一步,再用 ch 覆盖 pos 当前原字符
  7.         for (size_t end = _size; end >= pos + 1; --end)
  8.         {
  9.                 _str[end] = _str[end - 1];
  10.         }
  11.         _str[pos] = ch;
  12.         return *this;
  13. }
  14. my::string& my::string::insert(size_t pos, const char* str)
  15. {
  16.         assert(pos <= _size);
  17.         size_t len = strlen(str);
  18.         if (len != 0)
  19.         {
  20.                 reserve(_size += len);
  21.         // 将 pos 原位置与之后字符向后移动len步,再用 str 覆盖 pos 和之后原字符串
  22.                 for (size_t end = _size; end >= pos + len; --end)
  23.                 {
  24.                         _str[end] = _str[end - len];
  25.                 }
  26.                 strncpy(_str + pos, str, len);
  27.         }
  28.         return *this;
  29. }
复制代码
erase

这里只实现一个。
参考:std::string::erase
在 string.cpp 中:
  1. // 删除 pos ~ pos + len 位置上的元素,并返回该 string
  2. my::string& my::string::erase(size_t pos, size_t len)
  3. {
  4.         assert(pos < _size);
  5.         if (len > _size)                // len 默认值为 npos, 此时不能加,会溢出
  6.         {
  7.                 len = _size;
  8.         }
  9.                                                         // 若后面还有数据需移动
  10.         for (size_t end = pos; end < _size - len; ++end)
  11.         {
  12.                 _str[end] = _str[end + len];
  13.         }
  14.         _size = (_size - pos <= len ? pos : _size - len);
  15.         _str[_size] = '\0';                // '\0' 需单独处理
  16.         return *this;
  17. }
复制代码
find

这里只实现两个。
参考:std::string::find
在 string.cpp 中:
  1. // 返回 ch 在 string 中第一次出现的位置
  2. size_t my::string::find(char ch, size_t pos) const
  3. {
  4.         assert(pos <= _size);
  5.         size_t index = pos;
  6.         while (index < _size)
  7.         {
  8.                 if (_str[index] == ch)
  9.                 {
  10.                         break;
  11.                 }
  12.                 ++index;
  13.         }
  14.         return index == _size ? npos : index;
  15. }
  16. // 返回子串 str1 在 string 中第一次出现的位置
  17. size_t  my::string::find(const char* str1, size_t pos) const
  18. {
  19.         size_t len1 = strlen(str1);
  20.         assert(pos + len1 <= _size);
  21.         size_t index = pos;
  22.         while (index + len1 <= _size)
  23.         {
  24.                 if (strncmp(_str + index, str1, len1) == 0)
  25.                 {
  26.                         break;
  27.                 }
  28.                 ++index;
  29.         }
  30.         return index + len1 <= _size ? index : npos;
  31. }
复制代码
resize

参考:std::string::resize
在 my::string 中:
  1.         void resize(size_t n, char ch = '\0')
  2.         {
  3.             if (n > _size)
  4.             {
  5.                 reserve(n);
  6.                 for (int i = _size + 1; i < n; ++i)
  7.                 {
  8.                     _str[i] = ch;
  9.                 }
  10.             }
  11.             _str[_size = n] = '\0';
  12.         }
复制代码
构造、析构、赋值重载

参考:std::string::string
参考:std::string::~string
参考:std::string:perator=
在 my::string 中:
  1.         string(const char* str1 = "")
  2.             :_str(nullptr)
  3.             ,_size(0)
  4.             ,_capacity(0)
  5.         {
  6.             size_t len1 = strlen(str1);
  7.             reserve(len1);
  8.             memcpy(_str, str1, sizeof(char) * (len1 + 1));
  9.             _size = len1;
  10.         }
  11.         string(const string& str1)
  12.             :_str(nullptr)
  13.             ,_size(0)
  14.             ,_capacity(0)
  15.         {
  16.             reserve(str1.capacity());
  17.             memcpy(_str, str1._str, sizeof(char) * (str1._size + 1));
  18.             _size = str1._size;
  19.         }
  20.         ~string()
  21.         {
  22.             if (_str != nullptr)
  23.             {
  24.                 delete[] _str;
  25.                 _str = nullptr;
  26.             }
  27.             _size = _capacity = 0;
  28.         }
  29.         void swap(string& str1)
  30.         {
  31.             std::swap(_str, str1._str);
  32.             std::swap(_size, str1._size);
  33.             std::swap(_capacity, str1._capacity);
  34.         }
  35.         string& operator=(string str1)
  36.         {
  37.             swap(str1);
  38.             return *this;
  39.         }
复制代码
四、string 源代码

在 string.h 中:

  1. #pragma once#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>#include <cassert>#define MY_STRING_INIT_CAPACITY 4namespace my{    class string    {        friend std::ostream& operator<<(std::ostream& cout, const my::string& str1);        friend std::istream& operator>>(std::istream& cin, my::string& str1);    public:        typedef char* iterator;    public:        string(const char* str1 = "")
  2.             :_str(nullptr)
  3.             ,_size(0)
  4.             ,_capacity(0)
  5.         {
  6.             size_t len1 = strlen(str1);
  7.             reserve(len1);
  8.             memcpy(_str, str1, sizeof(char) * (len1 + 1));
  9.             _size = len1;
  10.         }
  11.         string(const string& str1)
  12.             :_str(nullptr)
  13.             ,_size(0)
  14.             ,_capacity(0)
  15.         {
  16.             reserve(str1.capacity());
  17.             memcpy(_str, str1._str, sizeof(char) * (str1._size + 1));
  18.             _size = str1._size;
  19.         }
  20.         ~string()
  21.         {
  22.             if (_str != nullptr)
  23.             {
  24.                 delete[] _str;
  25.                 _str = nullptr;
  26.             }
  27.             _size = _capacity = 0;
  28.         }
  29.         void swap(string& str1)
  30.         {
  31.             std::swap(_str, str1._str);
  32.             std::swap(_size, str1._size);
  33.             std::swap(_capacity, str1._capacity);
  34.         }
  35.         string& operator=(string str1)
  36.         {
  37.             swap(str1);
  38.             return *this;
  39.         }
  40.         //-----------------------------------------------------------        iterator begin()        {            return _str;        }        iterator end()        {            return _str + _size;        }        //-----------------------------------------------------------        void push_back(char ch)        {            insert(_size, ch);        }        void pop_back()        {            erase(_size - 1, 1);        }        string& operator+=(char ch)        {            return insert(_size, ch);        }        void append(const char* str1)        {            insert(_size, str1);        }        string& operator+=(const char* str1)        {            return insert(_size, str1);        }        void clear()        {            _str[_size = 0] = 0;        }        const char* c_str() const        {            return _str;        }        //-----------------------------------------------------------        size_t size() const        {            return _size;        }        size_t capacity() const        {            return _capacity - 1;        }        bool empty() const        {            return _size == 0;        }        void resize(size_t n, char ch = '\0')
  41.         {
  42.             if (n > _size)
  43.             {
  44.                 reserve(n);
  45.                 for (int i = _size + 1; i < n; ++i)
  46.                 {
  47.                     _str[i] = ch;
  48.                 }
  49.             }
  50.             _str[_size = n] = '\0';
  51.         }
  52.         void reserve(size_t n);        //-----------------------------------------------------------        char& operator[](size_t index)
  53.         {
  54.             return *(_str + index);
  55.         }
  56.         const char& operator[](size_t index) const
  57.         {
  58.             return *(_str + index);
  59.         }
  60.         //-----------------------------------------------------------        bool operator<(const string& str1)        {            return strcmp(c_str(), str1.c_str()) < 0;        }        bool operator>(const string& str1)        {            return strcmp(c_str(), str1.c_str()) > 0;        }        bool operator==(const string& str1)        {            return strcmp(c_str(), str1.c_str()) == 0;        }        bool operator<=(const string& str1)        {            return !(*this > str1);        }        bool operator>=(const string& str1)        {            return !(*this < str1);        }        bool operator!=(const string& str1)        {            return !(*this == str1);        }        //-----------------------------------------------------------        size_t find(char ch, size_t pos = 0) const;        size_t find(const char* str1, size_t pos = 0) const;        string& insert(size_t pos, char ch);        string& insert(size_t pos, const char* str);        string& erase(size_t pos = 0, size_t len = npos);        static const size_t npos = -1;    private:        char* _str;        size_t _capacity;        size_t _size;    };}
复制代码
在 string.cpp 中:

  1. #include "string.h"void my::string::reserve(size_t n)
  2. {
  3.         if (n + 1 <= _capacity)                        // 考虑末尾 '\0'
  4.         {
  5.                 return;
  6.         }
  7.         size_t newCapacity = _capacity == 0 ? MY_STRING_INIT_CAPACITY : _capacity * 2;
  8.         // n 仍然大于newCapacity时继续扩容
  9.         // newCapacity <= n 等价 newCapacity < n + 1
  10.         while (newCapacity <= n)       
  11.         {
  12.                 newCapacity <<= 1;
  13.         }
  14.         char* str1 = nullptr;                        // str1存储原空间地址       
  15.         std::swap(str1, _str);       
  16.         _str = new char[newCapacity];        // _str 新开空间后拷贝
  17.         // _size >= _capacity 只出现在初始化时(这时 _size == _capacity == 0)
  18.         // 以防止超出 _capacity 的非法内存访问
  19.         memcpy(_str, str1, sizeof(char) * (_size >= _capacity ? _capacity : _size + 1));
  20.         _capacity = newCapacity;
  21.         delete[] str1;
  22. }
  23. // 返回c在string中第一次出现的位置size_t my::string::find(char ch, size_t pos) const{        assert(pos <= _size);        size_t index = pos;        while (index < _size)        {                if (_str[index] == ch)                {                        break;                }                ++index;        }        return index == _size ? npos : index;}// 返回子串str1在string中第一次出现的位置size_t  my::string::find(const char* str1, size_t pos) const{        size_t len1 = strlen(str1);        assert(pos + len1 <= _size);        size_t index = pos;        while (index + len1 <= _size)        {                if (strncmp(_str + index, str1, len1) == 0)                {                        break;                }                ++index;        }        return index + len1 <= _size ? index : npos;}// 在 pos 位置上插入 字符ch / 字符串str,并返回该string
  24. my::string& my::string::insert(size_t pos, char ch)
  25. {
  26.         assert(pos <= _size);
  27.         reserve(++_size);
  28.         // 将 pos 原位置与之后字符向后移动一步,再用 ch 覆盖 pos 当前原字符
  29.         for (size_t end = _size; end >= pos + 1; --end)
  30.         {
  31.                 _str[end] = _str[end - 1];
  32.         }
  33.         _str[pos] = ch;
  34.         return *this;
  35. }
  36. my::string& my::string::insert(size_t pos, const char* str)
  37. {
  38.         assert(pos <= _size);
  39.         size_t len = strlen(str);
  40.         if (len != 0)
  41.         {
  42.                 reserve(_size += len);
  43.         // 将 pos 原位置与之后字符向后移动len步,再用 str 覆盖 pos 和之后原字符串
  44.                 for (size_t end = _size; end >= pos + len; --end)
  45.                 {
  46.                         _str[end] = _str[end - len];
  47.                 }
  48.                 strncpy(_str + pos, str, len);
  49.         }
  50.         return *this;
  51. }
  52. // 删除 pos ~ pos + len 位置上的元素,并返回该 string
  53. my::string& my::string::erase(size_t pos, size_t len)
  54. {
  55.         assert(pos < _size);
  56.         if (len > _size)                // len 默认值为 npos, 此时不能加,会溢出
  57.         {
  58.                 len = _size;
  59.         }
  60.                                                         // 若后面还有数据需移动
  61.         for (size_t end = pos; end < _size - len; ++end)
  62.         {
  63.                 _str[end] = _str[end + len];
  64.         }
  65.         _size = (_size - pos <= len ? pos : _size - len);
  66.         _str[_size] = '\0';                // '\0' 需单独处理
  67.         return *this;
  68. }
  69. std::ostream& my::operator<<(std::ostream& out, const my::string& str1){        out << str1.c_str();        return out;}std::istream& my::operator>>(std::istream& in, my::string& str1){        str1.clear();        // 缓冲        char buf[100] = { 0 };        char ch = in.get();        int i = 0;        while (ch != ' ' && ch != '\n')        {                buf[i++] = ch;                if (i >= 99)                {                        str1 += buf;                        i = 0;                }                ch = in.get();        }        if (i > 0)        {                buf[i] = '\0';                str1 += buf;        }        return in;}
复制代码
回复

使用道具 举报

登录后关闭弹窗

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