• 从零开始的C++(十)


    string 成员函数的模拟实现:

    1.构造函数

    1. string(const char* str = "")
    2. :_capacity(0)
    3. ,_size(0)
    4. ,_str(nullptr)
    5. {
    6. int len = strlen(str);
    7. _str = new char[len + 1];
    8. strcpy(_str, str);
    9. _size = _capacity = len;
    10. }
    11. void swap(string& s)
    12. {
    13. char* tmp = s._str;
    14. s._str = _str;
    15. _str = tmp;
    16. int tmp_int = s._size;
    17. s._size = _size;
    18. _size = tmp_int;
    19. tmp_int = s._capacity;
    20. s._capacity = _capacity;
    21. _capacity = tmp_int;
    22. }
    23. string(const string& s)
    24. {
    25. //法一
    26. /* int len = strlen(s._str);
    27. _str = new char[len + 1];
    28. strcpy(_str, s._str);
    29. _size = _capacity = len;*/
    30. //法二
    31. string tmp(s);
    32. swap(tmp);
    33. }

    对于传字符串的构造函数,利用参数化列表初始化了成员函数,再在函数内实现空间开辟、字符串拷贝、成员赋值。

    对于传同类对象的拷贝构造,一种方法是重新开辟空间,并把内容拷贝过去,实现深拷贝。一种方法是服用传字符串的构造函数,此时临时对象的内容就是所需要的内容,所以用一个swap函数将临时对象的成员内容和this指向的对象的成员内容互换,然后函数结束后对临时对象调用析构,处理了原本属于this指向的对象的内容的销毁。

    2.赋值函数:

    1. string& operator=(const string& s)
    2. {
    3. //法一
    4. /* _size = s._size;
    5. _capacity = s._capacity;
    6. char* tmp = new char[_capacity+1];
    7. strcpy(tmp, s._str);
    8. delete[] _str;
    9. _str = tmp;
    10. return *this;*/
    11. //法二
    12. string tmp(s._str);
    13. swap(tmp);
    14. }

    赋值函数的内容和传递对象的拷贝构造十分相似,都是将一个对象的内容深拷贝到另一个对象中,因此方法也有两种,原理和上述类似。

    3.析构函数:

    1. ~string()
    2. {
    3. delete[]_str;
    4. _size = _capacity = 0;
    5. }

    析构函数的主要作用就是销毁开辟的空间。

    4.插入内容:

    1. void reverse(size_t n)
    2. {
    3. if (n > _capacity)
    4. {
    5. _capacity = n;
    6. char* tmp = new char[_capacity + 1];
    7. strcpy(tmp, _str);
    8. _str = tmp;
    9. }
    10. }
    11. void push_back(char c)
    12. {
    13. //扩容
    14. if (_size == _capacity)
    15. {
    16. reverse(2 * _capacity + 1);
    17. }
    18. _str[_size] = c;
    19. _str[++_size] = '\0';
    20. }
    21. string& operator+=(char c)
    22. {
    23. push_back(c);
    24. return *this;
    25. }
    26. void append(const char* str)
    27. {
    28. int len = strlen(str);
    29. if (_size+len> _capacity)
    30. {
    31. reverse(_size + len);
    32. }
    33. strcat(_str, str);
    34. _size += len;
    35. }
    36. string& operator+=(const char* str)
    37. {
    38. append(str);
    39. return *this;
    40. }

    push_back()用于插入一个字符,append用于插入一个字符串,重载+=能实现插入一个字符或一个字符串,功能和push_back和append类似,因此直接复用,同时针对字符和字符串进行了函数重载。

    5.insert和erase:

    1. // 在pos位置上插入字符c/字符串str,并返回该字符的位置
    2. string& insert(size_t pos, char c)
    3. {
    4. assert(pos <= _size);
    5. *this += c;
    6. for (int i = _size; i > pos; i--)
    7. {
    8. _str[i] = _str[i - 1];
    9. }
    10. _str[pos] = c;
    11. _str[_size] = '\0';
    12. return *this;
    13. }
    14. string& insert(size_t pos, const char* str)
    15. {
    16. assert(pos <= _size);
    17. int len = _size + strlen(str);
    18. int len1 = strlen(str);
    19. reverse(len);
    20. for (int i =_size; i >=(int)pos ; i--)
    21. {
    22. _str[i+len1] = _str[i];
    23. }
    24. for (int i = pos,j=0; i < pos+len1; i++)
    25. {
    26. _str[i] = str[j++];
    27. }
    28. _size = len;
    29. return *this;
    30. }
    31. // 删除pos位置上的元素,并返回该元素的下一个位置
    32. string& erase(size_t pos, size_t len=-1)
    33. {
    34. assert(pos <_size&&pos>=0);
    35. if (len == -1||pos+len>=_size)
    36. {
    37. _size = pos;
    38. _str[_size] = '\0';
    39. }
    40. else
    41. {
    42. for (int i = pos + len; i < _size; i++)
    43. {
    44. _str[i - len] = _str[i];
    45. }
    46. _size -= len;
    47. _str[_size] = '\0';
    48. }
    49. return *this;
    50. }

    insert函数实现在pos位置插入一个字符或一个字符串,需要注意pos的类型是size_t,如果是头插用pos做循环条件可能会进行无限循环(即循环条件是大于或等于pos,此时pos等于0,但size_t类型永远大于或等于0)。

    erase函数实现在pos位置删除len个字符,如果len忽略或者len过大,相当于删除pos位置往后所有字符,因此需要判断len。

    6。流提取:

    1. istream& operator>>(istream& _cin, bit::string& s)
    2. {
    3. //充当临时缓冲区
    4. char tmp[101];
    5. s.clear();
    6. char ch;
    7. _cin.get(ch);
    8. int i = 0;
    9. while (ch != '\n' && ch != ' ')
    10. {
    11. if (i == 100)
    12. {
    13. tmp[i] = '\0';
    14. s += tmp;
    15. i = 0;
    16. }
    17. tmp[i++] = ch;
    18. _cin.get(ch);
    19. }
    20. if (i != 0)
    21. {
    22. tmp[i] = '\0';
    23. s += tmp;
    24. }
    25. return _cin;
    26. }

    对于流提取,本函数的实现方式是一个字符一个字符的插入,如果直接放入this指向对象中,会存在多次扩容,效率低。因此使用了一个临时缓冲区,缓冲区未满的时候内容放入缓冲区中,满了以后把缓冲区的内容全放入this指向的对象中,再清空缓冲区。需要注意,在退出循环后缓冲区中仍可能存在内容未放入this指向对象中,因此还需要放入一次。

  • 相关阅读:
    dubbo发送过程编码失败,会唤醒发送线程吗?
    飞机电子式模拟空速表的设计与制作
    JavaSE基础 (全网最全知识点)
    ThreadLocal 详解
    pg limit 的使用疑问 --chatGPT
    Nacos 动态服务发现详解
    Arctic——流式湖仓系统
    R语言时间序列数据算术运算:使用diff函数计算时间序列数据的逐次差分、使用除法将两个长度不等时间序列数据进行相除、使用固定值乘以指定的时间序列
    综述:大规模小目标检测
    vue 学习 -- day36(分析工程结构)
  • 原文地址:https://blog.csdn.net/yyssas/article/details/133859624