• C++初阶学习第七弹——探索STL奥秘(二)——string的模拟实现


    标准库中的string:C++初阶学习第六弹——string(1)——标准库中的string类-CSDN博客

    前言:

    在前面我们已经学习了如何使用标准库中的string类,但作为一个合格的程序员,我们不仅要会用,还要知道如何实现string中的类函数等内容,今天我们就来讲解一下string的模拟实现

    目录

    一、string类的构造

    二、string类的拷贝构造

    三、string类的析构函数

    四、string类的运算符重载

    1、operator=的传统写法

    2、operator=的现代写法

    五、代码实例

    六、总结


    string的模拟实现中最重要的就是string类的构造、拷贝构造、赋值运算符重载以及析构函数

    接下来我们就围绕这些重点进行学习

    一、string类的构造

    首先我们要清楚string类在底层实际上就是一个字符指针和许多类函数,所以它的类成员变量就是:

    1. private:
    2. char* _str;

    我们先把模拟构造给出来再来讲解:

    1. //为了区分标准库,我们用String
    2. class String
    3. {
    4. public:
    5. String(const char* str = "")
    6. {
    7. if (str == nullptr)
    8. {
    9. assert(false);
    10. return;
    11. }
    12. _str = new char[strlen(str) + 1];
    13. strcpy(_str, str);
    14. }
    15. void String_print()
    16. {
    17. cout << _str << endl;
    18. }
    19. private:
    20. char* _str;
    21. };
    22. int main()
    23. {
    24. String s1("abc");
    25. s1.String_print();
    26. return 0;
    27. }

    运行结果:

    相信一定有细心的朋友已经注意到我们在给参数时并没有给任何东西,原因如下:

    还有一点需要注意的是:我们在赋值时是创建一个新空间来储存,并不是直接赋值,这就涉及深拷贝的问题了,在下面我们讲拷贝构造的时候能更清晰的体现出来

    二、string类的拷贝构造

    模拟实现的代码如下:

    1. String(const String& s)
    2. : _str(new char[strlen(s._str) + 1])
    3. {
    4. strcpy(_str, s._str);
    5. }

    在这里我们主要来讲解一下深拷贝和浅拷贝的问题,我们放在一个完整的代码实例:

    1. class String
    2. {
    3. public:
    4. String(const char* str = "")
    5. {
    6. if (str == nullptr)
    7. {
    8. assert(false);
    9. return;
    10. }
    11. _str = new char[strlen(str) + 1];
    12. strcpy(_str, str);
    13. }
    14. String(const String& s)
    15. : _str(new char[strlen(s._str) + 1])
    16. {
    17. strcpy(_str, s._str);
    18. }
    19. void String_print()
    20. {
    21. cout << _str << endl;
    22. }
    23. private:
    24. char* _str;
    25. };
    26. int main()
    27. {
    28. String s1("abc");
    29. s1.String_print();
    30. String s2(s1);
    31. s2.String_print();
    32. return 0;
    33. }

    运行结果:

    错误示范:

    三、string类的析构函数

    由于string类对象不管以哪个方式创建时,都需要用new来开辟空间,所以string的析构函数写法为:

    1. ~String()
    2. {
    3. if (_str) //检查一下_str是否为空,如果为空就不用再释放空间了
    4. {
    5. delete[] _str;
    6. _str = nullptr;
    7. }
    8. }

    四、string类的运算符重载

    string类的运算符重载整体来说没啥难度,在这里我们也不做过多讲解,重点来讲解一下operator=的两种写法

    1、operator=的传统写法

    1. String& operator=(const String& s)
    2. {
    3. if (s._str != _str)
    4. {
    5. char* ptr = new char[strlen(s._str) + 1]; //+1是因为要多开辟一个空间存放\0
    6. strcpy(ptr, s._str);
    7. delete _str; //清空_str中可能有的数据
    8. _str = ptr;
    9. }
    10. return *this;
    11. }

    2、operator=的现代写法

    1. String& operator=(String s)
    2. {
    3. swap(_str, s._str); //swap函数算法库中存在,所以可以直接使用
    4. return *this;
    5. }

    单从篇幅上来比较,现代写法要比传统写法精简的多,那么它们两个究竟是如何实现它们的功能的呢?我们看下面的分析:

    · 传统写法:

    传统写法函数的参数是后值的引用,我们通过创建一个新的字符指针,并开辟空间接受后值,再把这个新创建的指针的地址传给我们的对象,从而实现了operator=的功能

    · 现代写法:

    现代写法则聪明的使用了算法库中的swap函数,从而让函数达到一个很精简的效果,该函数的参数是后值的临时拷贝,本来就是深拷贝,所以通过swap交换即可

    传统写法和现代写法的过程比较:

    五、代码实例

    1. //为了区分标准库,我们用String
    2. class String
    3. {
    4. public:
    5. String(const char* str = "")
    6. {
    7. if (str == nullptr)
    8. {
    9. assert(false);
    10. return;
    11. }
    12. _str = new char[strlen(str) + 1];
    13. strcpy(_str, str);
    14. }
    15. String(const String& s)
    16. : _str(new char[strlen(s._str) + 1])
    17. {
    18. strcpy(_str, s._str);
    19. }
    20. //现代写法
    21. String& operator=(String s)
    22. {
    23. swap(_str, s._str);
    24. return *this;
    25. }
    26. 传统写法
    27. //String& operator=(const String& s)
    28. //{
    29. // if (s._str != _str)
    30. // {
    31. // char* ptr = new char[strlen(s._str) + 1]; //+1是因为要多开辟一个空间存放\0
    32. // strcpy(ptr, s._str);
    33. // delete _str; //清空_str中可能有的数据
    34. // _str = ptr;
    35. // }
    36. // return *this;
    37. //}
    38. void String_print()
    39. {
    40. cout << _str << endl;
    41. }
    42. ~String()
    43. {
    44. if (_str) //检查一下_str是否为空,如果为空就不用再释放空间了
    45. {
    46. delete[] _str;
    47. _str = nullptr;
    48. }
    49. }
    50. private:
    51. char* _str;
    52. };
    53. int main()
    54. {
    55. String s1("abc");
    56. s1.String_print();
    57. String s2(s1);
    58. s2.String_print();
    59. String s3 = s2;
    60. s3.String_print();
    61. return 0;
    62. }

    运行结果:

    六、总结

    以上就是string模拟实现的比较重要的部分,其他类函数我们并没有写出来,但难度都不大,感兴趣的老铁可以自己摸索一下或者在网上搜一下它的实现

    感谢各位大佬观看,创作不易,还请一键三连!!!

  • 相关阅读:
    阿里云——OpenAPI使用——短信服务
    db2数据仓库集群的搭建
    conan入门(二十九):对阿里mnn进行Conan封装塈conans.CMake和conan.tools.cmake.CMake的区别
    css选中最后几个子元素
    NVIDIA Grace Hopper架构深度解析
    2.0、C语言——分支、循环语句
    GLIP,FLIP论文阅读
    搭建repo服务器管理多个git工程
    进程管理(四)
    技术分享 | orchetrator--安装一个高可用 orchestrator
  • 原文地址:https://blog.csdn.net/2301_80220607/article/details/138785146