• string模拟实现


    string模拟实现

    整体代码

    1. #pragma once
    2. #include<assert.h>
    3. namespace hqj
    4. {
    5.  class string
    6.  {
    7.     public:
    8.         friend ostream& operator<<(ostream& _cout, const hqj::string& s);
    9.         friend istream& operator>>(istream& _cin, hqj::string& s);
    10.         string(const char* str = "")//构造函数
    11.             :_size(strlen(str))
    12.             , _capacity(_size)
    13.         {
    14.             _str = new char[_capacity + 1];
    15.             strcpy(_str, str);
    16.         }
    17.         
    18.         string(const string& s)//拷贝构造函数
    19.             :_capacity(0)
    20.             , _size(0)
    21.             , _str(nullptr)
    22.         {
    23.             string tmp(s._str);//这里不能传s,原因是要调用构造函数而不是拷贝构造函数
    24.             swap(tmp);
    25.         }
    26.         ~string()//析构函数
    27.         {
    28.             delete[] _str;
    29.             _str = nullptr;
    30.             _size = 0;
    31.             _capacity = 0;
    32.         }
    33.         void reserve(size_t n)
    34.         {
    35.             if (n > _capacity)
    36.             {
    37.                 char* tmp = new char[n + 1];
    38.                 strcpy(tmp, _str);
    39.                 delete[] _str;
    40.                 _str = tmp;
    41.                 _capacity = n;
    42.             }
    43.         }
    44.         void push_back(char c)//尾插一个字符
    45.         {
    46.             if (_size >= _capacity)//不要去改变_capacity
    47.             {
    48.                
    49.                 reserve(_capacity == 0 ? 4 : _capacity * 2);
    50.             }
    51.             _str[_size= c;
    52.             _size++;
    53.             _str[_size= '\0';
    54.         }
    55.         void append(const char* str)
    56.         {
    57.             size_t len = strlen(str);
    58.             if (_size + len > _capacity)
    59.             {
    60.                 reserve(_size + len);
    61.             }
    62.             strcpy(_str + _size, str);
    63.             _size += len;
    64.         }
    65.         //+=运算符重载
    66.         string& operator+=(char c)
    67.         {
    68.             push_back(c);
    69.             return *this;
    70.         }
    71.         string& operator+=(const char* str)
    72.         {
    73.             append(str);
    74.             return *this;
    75.         }
    76.       
    77.         size_t capacity()const
    78.         {
    79.             return _capacity;
    80.         }
    81.         bool empty()const
    82.         {
    83.             return _size == 0;
    84.         }
    85.     
    86.         void clear()//清空string对象
    87.         {
    88.             _str[0= '\0';
    89.             _size = 0;
    90.         }
    91.         void swap(string& s)//string的交换函数,是现代写法的基础(包工头写法
    92.         {
    93.             std::swap(_str, s._str);
    94.             std::swap(_size, s._size);
    95.             std::swap(_capacity, s._capacity);
    96.         }
    97.         const size_t size()const//string有效数据个数
    98.         {
    99.             return _size;
    100.         }
    101.         //[]运算符重载
    102.         char& operator[](size_t index)
    103.         {
    104.             assert(index < _size);
    105.             return _str[index];
    106.         }
    107.         const char& operator[](size_t index)const
    108.         {
    109.             assert(index < _size);
    110.             return _str[index];
    111.         }
    112.         //迭代器部分
    113.         typedef char* iterator;
    114.         iterator begin()
    115.         {
    116.             return _str;
    117.         }
    118.         iterator end()
    119.         {
    120.             return _str + _size;
    121.         }
    122.         const iterator begin() const
    123.         {
    124.             return _str;
    125.         }
    126.         const iterator end() const
    127.         {
    128.             return _str + _size;
    129.         }
    130.         string& operator=(const string& s)
    131.         {
    132.             string tmp(s);
    133.             swap(tmp);
    134.             return *this;
    135.         }
    136.         //提供私有成员_str
    137.         const char* c_str()const
    138.         {
    139.             return _str;
    140.         }
    141.         // 返回c在String中第一次出现的位置
    142.         size_t find(char c, size_t pos = 0) const
    143.         {
    144.             assert(pos < _size);
    145.             for (int i = pos; i < _size; i++)
    146.             {
    147.                 if (_str[i] == c)
    148.                 {
    149.                     return i;
    150.                 }
    151.             }
    152.             return npos;
    153.         }
    154.         // 返回子串s在String中第一次出现的位置
    155.         size_t find(const char* s, size_t pos = 0) const
    156.         {
    157.             assert(pos < _size);
    158.             char* tmp = strstr(_str + pos, s);
    159.             if (tmp == nullptr)
    160.             {
    161.                 return npos;
    162.             }
    163.             return find(*tmp);
    164.         }
    165.         // 在pos位置上插入字符c/字符串str,并返回该字符的位置
    166.         string& insert(size_t pos, char c)
    167.         {
    168.             assert(pos <= _size);//pos=size相当于尾插
    169.             if (_size >= _capacity)//不要去改变_capacity
    170.             {
    171.                 reserve(_capacity == 0 ? 4 : _capacity * 2);
    172.             }
    173.             size_t end = _size + 1;
    174.             while (end != pos)
    175.             {
    176.                 _str[end= _str[end-1];
    177.                 end--;
    178.             }
    179.             _str[pos] = c;
    180.             _size++;
    181.             return *this;
    182.         }
    183.         string& insert(size_t pos, const char* str)
    184.         {
    185.             assert(pos <= _size);
    186.             size_t len = strlen(str);
    187.             if (_size+len >= _capacity)//不要去改变_capacity
    188.             {
    189.                 reserve(_size+len);
    190.             }
    191.             size_t end_new = _capacity;
    192.             size_t end_old = _size;
    193.             while (end_old > pos)
    194.             {
    195.                 _str[end_new] = _str[end_old];
    196.                 end_old--;
    197.                 end_new--;
    198.             }
    199.             _str[end_new] = _str[pos];
    200.             for (int i = 0; i < len; i++)
    201.             {
    202.                 _str[pos++= str[i];
    203.             }
    204.             _size+=len;
    205.             return *this;
    206.         }
    207.         // 删除pos位置上的元素,并返回该元素的下一个位置
    208.         void erase(size_t pos, size_t len = npos)
    209.         {
    210.             assert(pos < _size);
    211.             if (len == npos || pos + len >= _size)
    212.             {
    213.                 _str[pos] = '\0';
    214.                 _size = pos;
    215.             }
    216.             else
    217.             {
    218.                 size_t begin = pos + len;
    219.                 while (begin <= _size)
    220.                 {
    221.                     _str[begin - len] = _str[begin];
    222.                     ++begin;
    223.                 }
    224.                 _size -= len;
    225.             }
    226.         }
    227.         void resize(size_t n, char c = '\0')
    228.         {
    229.             size_t len = strlen(_str);
    230.             if (n > _capacity)
    231.             {
    232.                 reserve(n);
    233.                 for (int i = len + 1; i < _capacity; i++)
    234.                 {
    235.                     (*this) += c;
    236.                 }
    237.             }
    238.             else
    239.             {
    240.                 _str[n] = '\0';
    241.             }
    242.             _size = n;
    243.         }
    244.         bool operator<(const string& s)
    245.         {
    246.             if (strcmp(_str, s._str) < 0)
    247.             {
    248.                 return true;
    249.             }
    250.             return false;
    251.         }
    252.         bool operator<=(const string& s)
    253.         {
    254.             if ((*this) < s || (*this) == s)
    255.             {
    256.                 return true;
    257.             }
    258.             return false;
    259.         }
    260.         bool operator>(const string& s)
    261.         {
    262.             return !(*this <= s);
    263.         }
    264.         bool operator>=(const string& s)
    265.         {
    266.             return !(*this < s);
    267.         }
    268.         bool operator==(const string& s)
    269.         {
    270.             if (strcmp(_str, s._str) == 0)
    271.             {
    272.                 return true;
    273.             }
    274.             return false;
    275.         }
    276.         bool operator!=(const string& s)
    277.         {
    278.             return!((*this) == s);
    279.         }
    280.     private:
    281.         char* _str;
    282.         size_t _size;
    283.         size_t _capacity;
    284.     public:
    285.         const static size_t npos;
    286.  };
    287.     const size_t string::npos = -1;
    288.     //流插入流提取的运算符重载
    289.     ostream& operator<<(ostream& out, const hqj::string& s)
    290.     {
    291.         for (int i = 0; i < s.size(); i++)
    292.         {
    293.             out << s._str[i];
    294.         }
    295.         return out;
    296.     }
    297.    
    298.  /*   istream& operator>>(istream& in, string& s)
    299.     {
    300.         s.clear();
    301.         char buff[129];
    302.         size_t i = 0;
    303.         char ch;
    304.         ch = in.get();
    305.         while (ch != ' ' && ch != '\n')
    306.         {
    307.             buff[i++= ch;
    308.             if (i == 128)
    309.             {
    310.                 buff[i] = '\0';
    311.                 s += buff;
    312.                 i = 0;
    313.             }
    314.             ch = in.get();
    315.         }
    316.         if (i != 0)
    317.         {
    318.             buff[i] = '\0';
    319.             s += buff;
    320.         }
    321.         return in;
    322.     }*/
    323.     //自己的版本
    324.     istream& operator>>(istream& in, string& s)
    325.     {
    326.         char ch;
    327.         ch = in.get();
    328.         while (ch != '\n' && ch != '\0')
    329.         {
    330.             s += ch;
    331.             ch = in.get();
    332.         }
    333.         return in;
    334.     }

    私有成员

    • _str 是一个指向字符数组(C-style string)的指针,用于存储字符串的字符序列。

    • _size 是一个用于记录字符串当前长度的变量,即字符串中实际包含的字符数量。

    • _capacity 是一个用于记录字符串当前内存容量的变量,即分配给字符串的字符数组的大小。

    • 这样的设计是为了支持动态字符串的存储和操作。当字符串长度超过当前内存容量时,可以通过重新分配更大的内存空间来保证字符串的存储能力。而 _str 指针则可以指向新分配的内存空间,以容纳更多的字符序列。

    1.  private:
    2.         char* _str;
    3.         size_t _size;
    4.         size_t _capacity;

    构造函数

    • 构造函数中的语法 const char* str = "" 定义了一个默认参数。如果在创建对象时不传入参数,那么默认会将一个空字符串赋值给 str。如果传入参数,则使用传入的字符串来初始化新对象。

    • 在构造函数中,首先使用 C 标准库函数 strlen 来计算 str 字符串的长度,并将其保存到成员变量 _size 中。然后,根据字符串长度计算出需要分配的存储空间,并将其保存到成员变量 _capacity 中。

    • 接下来使用 new 运算符在堆上动态分配内存,分配的空间大小为 _capacity + 1,因为字符串末尾要以字符 '\0' 结束。然后使用 C 标准库函数 strcpy 将 str 字符串的内容复制到新分配的内存空间中。

    • 最后,将指针变量 _str 指向新分配的内存空间,完成 C++ 字符串的构造过程。

    1. string(const char* str = "")//构造函数
    2.             :_size(strlen(str))
    3.             , _capacity(_size)
    4.         {
    5.             _str = new char[_capacity + 1];
    6.             strcpy(_str, str);
    7.         }

    拷贝构造函数

    • 在拷贝构造函数中,首先初始化成员变量 _capacity、_size 和 _str,它们分别表示字符串的容量、大小和存储内容的指针。

    • 然后,在构造函数内部创建了一个名为 tmp 的临时字符串对象,并通过传入的参数 s 的 _str 成员变量来初始化它。这里不能直接传入 s,而是使用 s._str,是因为直接传入 s 会导致递归调用拷贝构造函数,而我们需要调用的是构造函数。

    • 接下来,通过调用 swap 函数,将临时字符串对象 tmp 和当前对象的内容进行交换。这一步中,实际上是交换了 _str 指针指向的内存空间,从而实现了将原始字符串对象的内容复制给新对象的目的。

    • 最终,根据交换后的内容,临时字符串对象 tmp 会自动被销毁,同时也会自动释放内存空间。

    1.  string(const string& s)//拷贝构造函数
    2.             :_capacity(0)
    3.             , _size(0)
    4.             , _str(nullptr)
    5.         {
    6.             string tmp(s._str);//这里不能传s,原因是要调用构造函数而不是拷贝构造函数
    7.             swap(tmp);
    8.         }

    赋值运算符的重载

    • 在赋值运算符重载函数中,首先创建了一个名为 tmp 的临时字符串对象,并通过传入的参数 s 调用拷贝构造函数初始化它。

    • 接下来,调用 swap 函数,将临时字符串对象 tmp 和当前字符串对象的内容进行交换。这一步中,实际上是交换了 _str 指针指向的内存空间,从而实现了将原始字符串对象的内容复制给当前对象的目的。

    • 最后,返回当前字符串对象的引用,以支持链式赋值操作。

    1.     stringoperator=(const string& s)
    2.         {
    3.             string tmp(s);
    4.             swap(tmp);
    5.             return *this;
    6.         }

    析构函数

    • 在析构函数中,首先使用 delete[] 关键字释放之前在堆上动态分配的 _str 成员变量指向的内存空间。这是为了避免发生内存泄漏,释放资源以确保不再使用该内存空间。

    • 接下来,将指针 _str 赋值为 nullptr,以防止在使用已释放的内存时发生未定义的行为。

    • 最后,将成员变量 _size 和 _capacity 的值都设为 0,以标记字符串的大小和容量为 0,表示该字符串对象已经被析构销毁。

    1.   ~string()//析构函数
    2.         {
    3.             delete[] _str;
    4.             _str = nullptr;
    5.             _size = 0;
    6.             _capacity = 0;
    7.         }

    resize函数

    • resize 函数接受两个参数:新的字符串大小 n 和要填充的字符 c(可选,默认为结束符 '\0')。该函数首先使用 strlen 函数获取当前字符串的长度 len。然后根据不同情况进行处理:

    • 如果新的字符串大小 n 大于字符串的容量 _capacity,表示需要增加字符串的容量以容纳更多的字符。这里通过调用 reserve 函数来增加字符串的容量,保证足够存放 n 个字符,并且在剩余空间中填充字符 c。循环从 len + 1 开始,一直到容量 _capacity,将字符 c 追加到字符串中。

    • 如果新的字符串大小 n 不大于字符串的容量 _capacity,表示不需要增加字符串的容量。此时,如果 n 小于当前字符串的长度 len,需要将字符串截断到指定大小,即将第 n 个字符设置为结束符 '\0'。如果 n 大于等于当前字符串的长度 len,则不需要进行额外操作。

    • 最后,更新字符串的大小 _size 为新的字符串大小 n。

    1. void resize(size_t n, char c = '\0')
    2.         {
    3.             size_t len = strlen(_str);
    4.             if (n > _capacity)
    5.             {
    6.                 reserve(n);
    7.                 for (int i = len + 1; i < _capacity; i++)
    8.                 {
    9.                     (*this) += c;
    10.                 }
    11.             }
    12.             else
    13.             {
    14.                 _str[n] = '\0';
    15.             }
    16.             _size = n;
    17.         }

    reserve函数

    • 这是一个 C++ 字符串类中的 reserve 函数,用于预留足够的容量来存储字符串。

    • 在 reserve 函数中,首先判断传入的参数 n 是否大于当前字符串的容量 _capacity。如果大于,则需要进行扩容操作。

    • 创建了一个名为 tmp 的字符数组指针,通过使用 new 运算符在堆上分配了 n+1 个字符的内存空间。这里 n+1 是为了包含字符串的结尾字符 \0。

    • 然后,使用 strcpy 函数将原始字符串 _str 的内容复制到新分配的内存空间 tmp 中。

    • 接下来,使用 delete[] 运算符释放原始字符串 _str 指向的内存空间,以防止出现内存泄漏。

    • 将指针 _str 更新为指向新分配的内存空间 tmp,使其指向新的字符串内容。

    • 最后,将字符串的容量 _capacity 更新为 n,表示字符串已经具备了预留的容量。

    1. void reserve(size_t n)
    2.         {
    3.             if (n > _capacity)
    4.             {
    5.                 char* tmp = new char[n + 1];
    6.                 strcpy(tmp, _str);
    7.                 delete[] _str;
    8.                 _str = tmp;
    9.                 _capacity = n;
    10.             }
    11.         }

    push_back 函数

    • 在 push_back 函数中,首先判断当前字符串的大小 _size 是否已经达到了容量 _capacity,如果已经达到,则通过调用字符串类内部的 reserve 函数进行扩容,以腾出更多的空间来存储新的字符。

    • 当确保有足够的容量后,将字符 c 插入到字符串的末尾 _str[_size],并将 _size 的值加一。最后,在末尾添加一个空字符 \0,保证字符串的完整性。

    1. void push_back(char c)//尾插一个字符
    2.         {
    3.             if (_size >= _capacity)//不要去改变_capacity
    4.             {
    5.                
    6.                 reserve(_capacity == 0 ? 4 : _capacity * 2);
    7.             }
    8.             _str[_size= c;
    9.             _size++;
    10.             _str[_size= '\0';
    11.         }

    append 函数

    • 在 append 函数中,首先获取待追加字符数组 str 的长度 len,使用 strlen 函数计算得到。

    • 接着,判断当前字符串的大小 _size 加上待追加字符数组的长度 len 是否超过了容量 _capacity。如果超过了容量,则通过调用字符串类内部的 reserve 函数进行扩容,以腾出足够的空间来存储新的字符。

    • 当确保有足够的容量后,使用 strcpy 函数将字符数组 str 的内容复制到字符串的末尾 _str + _size,即从 _str 的第 _size 个位置开始复制。

    • 最后,将 _size 的值增加 len,表示字符串的大小已经扩展到了追加后的长度。

    • 需要注意的是,为了保证字符串的完整性,最后需要手动添加一个空字符 \0,以结束字符串。

    • 与 push_back 函数相比,append 函数可以一次性追加多个字符,效率较高。适用于需要一次性追加多个字符或者字符数组的情况。而 push_back 则适用于单个字符的追加。

    1.  void append(const char* str)
    2.         {
    3.             size_t len = strlen(str);
    4.             if (_size + len > _capacity)
    5.             {
    6.                 reserve(_size + len);
    7.             }
    8.             strcpy(_str + _size, str);
    9.             _size += len;
    10.         }

    []运算符重载

    • 在函数体内,通过使用 assert 宏来判断指定的下标是否越界,如果越界则会触发一个断言错误并终止程序的执行,从而避免了对无效位置进行访问。

    • 然后,根据运算符的重载类型(即 const 和非 const),返回私有成员变量 _str 中对应下标位置的字符的引用或常量引用,从而实现对字符串中字符的读写操作。

    • 使用 [] 运算符可以方便地访问字符串对象中的任意字符,类似于数组的使用方式。

    1.  //[]运算符重载
    2.         char& operator[](size_t index)
    3.         {
    4.             assert(index < _size);
    5.             return _str[index];
    6.         }
    7.         const char& operator[](size_t index)const
    8.         {
    9.             assert(index < _size);
    10.             return _str[index];
    11.         }

    +=运算符重载

    • 第一个重载函数 operator+=(char c) 接受一个字符 c 作为参数。在函数体内,调用了字符串类的 push_back 函数,将字符 c 追加到字符串的末尾。然后,返回当前字符串对象的引用 *this。

    • 第二个重载函数 operator+=(const char* str) 接受一个字符数组 str 作为参数。在函数体内,调用了字符串类的 append 函数,将字符数组 str 追加到字符串的末尾。然后,返回当前字符串对象的引用 *this。

    1.   string& operator+=(char c)
    2.         {
    3.             push_back(c);
    4.             return *this;
    5.         }
    6.         string& operator+=(const char* str)
    7.         {
    8.             append(str);
    9.             return *this;
    10.         }

    capacity函数

    • 这是 C++ 字符串类中的 capacity 函数,用于获取字符串对象的容量大小。

    • 在函数体内,直接返回私有成员变量 _capacity 的值。该变量表示字符串对象已经预分配的空间大小,即在不扩容的情况下,该字符串对象最多可以存储多少个字符。

    • 使用 capacity 函数可以帮助我们了解当前字符串对象的容量大小,以便更好地管理内存分配和释放,避免浪费或者不足的情况发生。

    1.   size_t capacity()const
    2.         {
    3.             return _capacity;
    4.         }

    empty函数

    • 这是 C++ 字符串类中的 empty 函数,用于判断字符串对象是否为空。

    • 在函数体内,通过比较私有成员变量 _size 是否等于 0,来判断字符串是否为空。如果 _size 等于 0,表示字符串中没有任何字符,即为空;否则,表示字符串中至少包含一个字符,即不为空。

    1.  bool empty()const
    2.         {
    3.             return _size == 0;
    4.         }
    5.     

    clear函数

    • 在函数体内,首先将字符串对象 _str 的第一个字符 _str[0] 设置为 '\0',即空字符,表示字符串为空。

    • 然后,将私有成员变量 _size 设置为 0,表示字符串中没有任何字符。

    • 通过调用 clear 函数可以将字符串对象清空,使其不包含任何字符。

    1.  void clear()//清空string对象
    2.         {
    3.             _str[0= '\0';
    4.             _size = 0;
    5.         }

    swap函数

    • 在函数体内,通过使用 std::swap 函数来交换私有成员变量 _str、_size 和 _capacity 与另一个字符串对象 s 的对应成员变量的值。

    • std::swap 是 C++ 标准库中的一个通用函数模板,用于交换两个对象的值。它会根据对象的类型自动选择最高效的交换方式,从而避免了手动实现交换逻辑的繁琐和潜在的错误。

    • 通过调用 swap 函数,可以快速且安全地交换两个字符串对象的内容。

    1.  void swap(string& s)//string的交换函数,是现代写法的基础(包工头写法
    2.         {
    3.             std::swap(_str, s._str);
    4.             std::swap(_size, s._size);
    5.             std::swap(_capacity, s._capacity);
    6.         }

    size函数

    • 在函数体内,直接返回私有成员变量 _size 的值,表示字符串中包含 _size 个字符,即为有效数据的个数。

    • 使用 size 函数可以方便地获取字符串中字符的数量,可以用于数组越界和其他处理中。

    1.   const size_t size()const//string有效数据个数
    2.         {
    3.             return _size;
    4.         }

    迭代器部分的模拟实现

    • 在代码中,使用 typedef 关键字定义了一个名为 iterator 的别名,它表示指向字符的指针类型。

    • 然后,重载了 begin() 和 end() 函数,分别用于返回字符串对象的起始位置和结束位置的迭代器。

    • 对于非常量对象,begin() 函数直接返回私有成员变量 _str,即指向字符串开头的指针。而 end() 函数返回 _str + _size,即指向字符串结尾下一个位置的指针。

    • 对于常量对象,也重载了 begin() 和 end() 函数,返回相同的迭代器,但是声明为常量迭代器,表示在常量对象上不允许修改字符值。

    • 通过返回迭代器,可以方便地遍历字符串对象中的字符,并进行各种操作。

    1.  //迭代器部分
    2.         typedef char* iterator;
    3.         iterator begin()
    4.         {
    5.             return _str;
    6.         }
    7.         iterator end()
    8.         {
    9.             return _str + _size;
    10.         }
    11.         const iterator begin() const
    12.         {
    13.             return _str;
    14.         }
    15.         const iterator end() const
    16.         {
    17.             return _str + _size;
    18.         }

    c_str函数

    • c_str() 函数通常用于将字符串对象转换为 C 风格的字符串,以便与需要接受 C 风格字符串作为参数的函数进行交互。

    1. //提供私有成员_str
    2.         const charc_str()const
    3.         {
    4.             return _str;
    5.         }

    find函数

    • 函数的参数包括一个指向字符数组的指针 s 和一个可选的起始搜索位置 pos(默认为0)。

    • 首先,使用 assert 断言确保 pos 的值小于字符串的长度 _size,以避免越界访问。

    • 接下来,使用标准库函数 strstr 在字符串 _str 的 pos 位置之后搜索指定的子串 s。如果找到了匹配的子串,则 strstr 函数返回指向该子串的指针;如果没有找到,则返回空指针。

    • 如果 tmp 是空指针(即找不到匹配的子串),则表示查找失败,函数返回特殊值 npos(通常定义为 size_t(-1),表示无效的位置)。

    • 如果找到了匹配的子串,函数会继续调用 find 函数,传入子串的第一个字符 *tmp,以在整个字符串中找到该字符第一次出现的位置,并将其作为结果返回。

    • 需要注意的是,find 函数返回的是子串第一次出现的位置,而不是子串本身。如果需要获取子串本身,可以使用字符串类的 substr 函数进行切片操作。

    • 此外,该代码中的 find 函数是一个 const 成员函数,表示它不会修改字符串对象的内容。

    1.   size_t find(const char* s, size_t pos = 0) const
    2.         {
    3.             assert(pos < _size);
    4.             char* tmp = strstr(_str + pos, s);
    5.             if (tmp == nullptr)
    6.             {
    7.                 return npos;
    8.             }
    9.             return find(*tmp);
    10.         }

    insert函数

    • 第一个 insert 函数接受两个参数:一个是要插入的字符 c,另一个是插入位置 pos。该函数首先使用断言 assert 确保插入位置不超出字符串的范围。然后,如果字符串当前的长度 _size 已经达到了其容量 _capacity,则通过调用 reserve 函数增加字符串的空间以容纳新字符。接下来,将 pos 之后的所有字符依次向后挪一位,为新字符腾出空间。最后,将新字符插入到指定位置,更新字符串的长度并返回字符串对象本身的引用。

    • 第二个 insert 函数与第一个函数类似,但它接受的参数是一个字符指针 str,表示要插入的字符串。该函数的实现类似于第一个函数,只不过需要多次插入字符,并且需要移动更多的字符位置。在插入前,该函数还会先计算待插入字符串的长度 len。最后,更新字符串的长度并返回字符串对象本身的引用。

    1.  // 在pos位置上插入字符c/字符串str,并返回该字符的位置
    2.         string& insert(size_t pos, char c)
    3.         {
    4.             assert(pos <= _size);//pos=size相当于尾插
    5.             if (_size >= _capacity)//不要去改变_capacity
    6.             {
    7.                 reserve(_capacity == 0 ? 4 : _capacity * 2);
    8.             }
    9.             size_t end = _size + 1;
    10.             while (end != pos)
    11.             {
    12.                 _str[end= _str[end-1];
    13.                 end--;
    14.             }
    15.             _str[pos] = c;
    16.             _size++;
    17.             return *this;
    18.         }
    19.         string& insert(size_t pos, const char* str)
    20.         {
    21.             assert(pos <= _size);
    22.             size_t len = strlen(str);
    23.             if (_size+len >= _capacity)//不要去改变_capacity
    24.             {
    25.                 reserve(_size+len);
    26.             }
    27.             size_t end_new = _capacity;
    28.             size_t end_old = _size;
    29.             while (end_old > pos)
    30.             {
    31.                 _str[end_new] = _str[end_old];
    32.                 end_old--;
    33.                 end_new--;
    34.             }
    35.             _str[end_new] = _str[pos];
    36.             for (int i = 0; i < len; i++)
    37.             {
    38.                 _str[pos++= str[i];
    39.             }
    40.             _size+=len;
    41.             return *this;
    42.         }

    erase函数

    • erase 函数接受两个参数:要删除的元素的起始位置 pos,和要删除的元素的长度 len(可选,默认为 npos)。该函数首先使用断言 assert 确保删除位置不超出字符串的范围。然后根据 len 的值进行不同的处理:

    • 如果 len 的值为默认值 npos 或者 pos + len 大于等于字符串的长度 _size,表示要删除 pos 位置之后的所有元素,则将 pos 位置上的元素设置为结束符 '\0',并更新字符串的长度 _size 为 pos。

    • 否则,需要删除指定位置 pos 后面的 len 个元素。首先定义一个变量 begin,表示要删除的元素之后的第一个元素的位置。然后通过循环将 begin 位置及其后面的所有元素向前挪动 len 个位置,以覆盖要删除的元素。最后,更新字符串的长度 _size 减去 len。

    • 这样,删除成功后,字符串中就会被删除的元素占据的位置填补上相应的元素,并且字符串的长度也会相应调整。

    1.   // 删除pos位置上的元素,并返回该元素的下一个位置
    2.         void erase(size_t pos, size_t len = npos)
    3.         {
    4.             assert(pos < _size);
    5.             if (len == npos || pos + len >= _size)
    6.             {
    7.                 _str[pos] = '\0';
    8.                 _size = pos;
    9.             }
    10.             else
    11.             {
    12.                 size_t begin = pos + len;
    13.                 while (begin <= _size)
    14.                 {
    15.                     _str[begin - len] = _str[begin];
    16.                     ++begin;
    17.                 }
    18.                 _size -= len;
    19.             }
    20.         }

    比较运算符的重载

    • 首先,这些比较运算符都接受一个字符串对象 s 作为参数,并以引用形式传递。接下来,按照运算符的定义进行逐个实现:

    • 小于运算符(<)通过调用 strcmp 函数比较当前字符串 _str 和参数字符串 s._str 的大小。如果 _str 小于 s._str,则返回 true;否则返回 false。

    • 小于等于运算符(<=)通过在小于运算符之后添加一个等于运算符组成。如果当前字符串小于 s 或者当前字符串等于 s,则返回 true;否则返回 false。

    • 大于运算符(>)通过在小于等于运算符之前添加逻辑非运算符(!)来实现。如果当前字符串不小于等于 s,即大于 s,则返回 true;否则返回 false。

    • 大于等于运算符(>=)通过在大于运算符之前添加逻辑非运算符来实现。如果当前字符串不大于 s,即小于 s,则返回 true;否则返回 false。

    • 等于运算符(==)通过调用 strcmp 函数比较当前字符串和参数字符串的大小。如果相等,则返回 true;否则返回 false。

    • 不等于运算符(!=)通过在等于运算符之前添加逻辑非运算符来实现。如果当前字符串不等于 s,则返回 true;否则返回 false。

    • 这样,就可以使用比较运算符对字符串对象进行大小比较操作。

    1.    bool operator<(const string& s)
    2.         {
    3.             if (strcmp(_str, s._str) < 0)
    4.             {
    5.                 return true;
    6.             }
    7.             return false;
    8.         }
    9.         bool operator<=(const string& s)
    10.         {
    11.             if ((*this) < s || (*this) == s)
    12.             {
    13.                 return true;
    14.             }
    15.             return false;
    16.         }
    17.         bool operator>(const string& s)
    18.         {
    19.             return !(*this <= s);
    20.         }
    21.         bool operator>=(const string& s)
    22.         {
    23.             return !(*this < s);
    24.         }
    25.         bool operator==(const string& s)
    26.         {
    27.             if (strcmp(_str, s._str) == 0)
    28.             {
    29.                 return true;
    30.             }
    31.             return false;
    32.         }
    33.         bool operator!=(const string& s)
    34.         {
    35.             return!((*this) == s);
    36.         }

    流插入流提取运算符重载

    • 首先,流插入运算符重载函数接受一个输出流对象 out 和一个字符串对象 s 作为参数,并以引用形式传递。实现过程中遍历字符串 _str 的每个字符并输出到 out 流中,最后返回输出流对象 out。

    • 比较而言,流提取运算符重载函数接受一个输入流对象 in 和一个自定义的字符串对象 s 作为参数。实现过程中逐个读取输入流中的字符,如果字符不是换行符或者字符串终止符,则将其添加到字符串对象 s 中,最后返回输入流对象 in。

    1. //流插入流提取的运算符重载
    2.     ostream& operator<<(ostream& out, const hqj::string& s)
    3.     {
    4.         for (int i = 0; i < s.size(); i++)
    5.         {
    6.             out << s._str[i];
    7.         }
    8.         return out;
    9.     }
    10. //自己的版本
    11.     istream& operator>>(istream& in, string& s)
    12.     {
    13.         char ch;
    14.         ch = in.get();
    15.         while (ch != '\n' && ch != '\0')
    16.         {
    17.             s += ch;
    18.             ch = in.get();
    19.         }
    20.         return in;
    21.     }
  • 相关阅读:
    kubernetes集群编排(8)
    WPF 依赖属性原理、 附加属性
    【数据结构】二叉树的前序遍历(七)
    20个Java集合面试问题和答案
    商城采集(淘宝京东1688拼多多)商品详情API接口
    Android SDK与JDK区别和联系
    QDU暑假集训第一周限时训练1
    [附源码]SSM计算机毕业设计校园超市进销存管理系统JAVA
    ASUS华硕天选4笔记本FA507NU7735H_4050原装出厂Win11系统
    系列六、JVM的内存结构【栈】
  • 原文地址:https://blog.csdn.net/ZHENGZJM/article/details/133466725