【C++】运算符重载案例 - 字符串类 ② ( 重载 等号 = 运算符 | 重载 数组下标 [] 操作符 | 完整代码示例 )

电玩女神 2024-02-23 01:49 142阅读 0赞

文章目录

  • 一、重载 等号 = 运算符
    • 1、等号 = 运算符 与 拷贝构造函数
    • 2、重载 等号 = 运算符 - 右操作数为 String 对象
    • 3、不同的右操作数对应的 重载运算符函数
  • 二、重载 下标 [] 运算符
  • 三、完整代码示例
    • 1、String.h 类头文件
    • 2、String.cpp 类实现
    • 3、Test.cpp 测试类
    • 4、执行结果

一、重载 等号 = 运算符


1、等号 = 运算符 与 拷贝构造函数

等号 = 操作符 的 作用是 使用一个现有对象 为 另外一个现有对象赋值 ;

  • 注意与 拷贝构造函数 区分 , 拷贝构造函数是 使用一个先有对象 为 一个新的对象进行初始化 ;
  • 下面的代码中 , 分别调用 等号操作符 和 拷贝构造函数 ;

    String s1, s2;
    s1 = s2; // 这是使用 等号操作符 进行运算
    String s3 = s2; // 这是使用 拷贝构造函数

2、重载 等号 = 运算符 - 右操作数为 String 对象

使用 成员函数 实现 重载 等号 = 运算符 :

  • 首先 , 写出函数名 , 函数名规则为 “ operate “ 后面跟上要重载的运算符 ,

    • 2 2 2 个对象 Student s1, s2 之间进行 等号运算 , 使用一个现有对象 为 另外一个现有对象赋值 ;
    • 使用时用法为 s1 = s2 ;
    • 函数名是 operator= ;

    operator=

  • 然后 , 根据操作数 写出函数参数 , 参数一般都是 对象的引用 ;

    • 等号运算符 使用时用法为 s1 = s2 ;
    • 左操作数 : 其中 左操作数 是 s1 , 这里通过 this 指针调用 , 不需要声明在参数中 ;
    • 右操作数 - 情况 ① : 右操作数 也是 String 对象 ; 该操作数需要声明在参数中 , 注意 普通数据类型 直接声明 , 对象数据类型 需要声明 为 引用类型 ;
    • 上述两个是对象类型 , 对象一般传入 指针 或 引用 , 由于是基础数据类型 , 这里传入基础数据类型 ; 如果是 对象类型 , 则传入引用 ;
    • 右操作数 - 情况 ② : 还有一种情况是 s1 = "Tom" 的用法 , 这样 右操作数 是 char* 类型的字符串 ;

    operator=(const String& s) // 传入 String 对象 , 使用 const 修饰参数 , 防止传入的对象被修改
    operator=(const char* p) // 传入字符串值

  • 再后 , 根据业务完善返回值 , 返回值可以是 引用 / 指针 / 元素 ;

    • 此处返回值返回 String& 对象引用 , 可用于其它链式调用 ;
    • 如果返回 String 对象 , 则是一次性的匿名对象 ;

    String& operator=(const String& s) // 传入 String 对象 , 使用 const 修饰参数 , 防止传入的对象被修改
    String& operator=(const char* p) // 传入字符串值

  • 最后 , 实现函数体 , 编写具体的运算符操作业务逻辑 ;

    • 先把本对象已分配的内存释放掉 ;
    • 再进行赋值操作 ;

3、不同的右操作数对应的 重载运算符函数

不同的右操作数对应的 重载运算符函数 :

  • 右操作数是 String 对象的情况 :

    // 重载等号 = 操作符 , 右操作数是 String 对象的情况
    String& String::operator=(const String& s)
    {

    1. // 先处理本对象已分配的内存
    2. if (this->m_p != NULL)
    3. {
    4. // 之前使用 new 分配的内存
    5. // 释放内存就需要使用 delete
    6. // 使用 malloc 分配的内存需要使用 free 释放
    7. delete[] this->m_p;
    8. // 设置指针指为空 , 避免出现野指针
    9. this->m_p = NULL;
    10. // 设置字符串长度为 0
    11. this->m_len = 0;
    12. }
    13. // 拷贝字符串长度
    14. // 注意 : 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'
    15. this->m_len = s.m_len;
    16. // 使用 new 关键字为 char* m_p; 指针分配内存
    17. // 对于基础数据类型 new 等同于 malloc
    18. this->m_p = new char[this->m_len + 1];
    19. // 拷贝字符串到 m_p 指向的内存中
    20. strcpy(this->m_p, s.m_p);
    21. cout << "调用重载等号 = 操作符函数 String& String::operator=(const String& s)" << endl;
    22. return *this;

    }

  • 右操作数为 字符串指针 的情况 :

    // 重载等号 = 操作符 , 右操作数是 字符串常量值 的情况
    String& String::operator=(const char* p)
    {

    1. // 先处理本对象已分配的内存
    2. if (this->m_p != NULL)
    3. {
    4. // 之前使用 new 分配的内存
    5. // 释放内存就需要使用 delete
    6. // 使用 malloc 分配的内存需要使用 free 释放
    7. delete[] this->m_p;
    8. // 设置指针指为空 , 避免出现野指针
    9. this->m_p = NULL;
    10. // 设置字符串长度为 0
    11. this->m_len = 0;
    12. }
    13. // 拷贝字符串长度
    14. // 注意 : 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'
    15. this->m_len = strlen(p);
    16. // 使用 new 关键字为 char* m_p; 指针分配内存
    17. // 对于基础数据类型 new 等同于 malloc
    18. this->m_p = new char[this->m_len + 1];
    19. // 拷贝字符串到 m_p 指向的内存中
    20. strcpy(this->m_p, p);
    21. cout << "调用重载等号 = 操作符函数 String& String::operator=(const char* p)" << endl;
    22. return *this;

    }

二、重载 下标 [] 运算符


使用 成员函数 实现 重载 下标 [] 运算符 :

  • 首先 , 写出函数名 , 函数名规则为 “ operate “ 后面跟上要重载的运算符 ,

    • 下标 [] 运算符 , 使用时用法为 s[10] ;
    • 重载 下标 [] 运算符 函数名是 operator[] ;

    operator[]

  • 然后 , 根据操作数 写出函数参数 , 参数一般都是 对象的引用 ;

    • 下标 运算符 使用时用法为 s[10] ;
    • 左操作数 : 其中 左操作数 是 s 对象 , 这里通过 this 指针调用 , 不需要声明在参数中 ;
    • 右操作数 : 右操作数 是 int 类型 索引值 ;

    operator

  • 再后 , 根据业务完善返回值 , 返回值可以是 引用 / 指针 / 元素 ;

    • 此处返回值 是 char 类型的 , 返回具体字符串指定索引的 char 类型字符 ;
    • char 字符是内存中的一个地址中的值 , 这里返回引用类型 ;

    char& operator

  • 最后 , 实现函数体 , 编写具体的运算符操作业务逻辑 ;

    // 重载 数组下标 [] 操作符
    char& String::operator
    {

    1. // 直接返回对应 i 索引字符
    2. return this->m_p[i];

    }

三、完整代码示例


1、String.h 类头文件

  1. #pragma once
  2. #include "iostream"
  3. using namespace std;
  4. class String
  5. {
  6. public:
  7. // 默认的无参构造函数
  8. String();
  9. // 有参构造函数 , 接收一个 char* 类型字符串指针
  10. String(const char* p);
  11. // 拷贝构造函数 , 使用 String 对象初始化 对象值
  12. String(const String& s);
  13. // 析构函数
  14. ~String();
  15. public:
  16. // 重载等号 = 操作符 , 右操作数是 String 对象的情况
  17. String& operator=(const String& s);
  18. // 重载等号 = 操作符 , 右操作数是 字符串常量值 的情况
  19. String& operator=(const char* p);
  20. // 重载 数组下标 [] 操作符
  21. char& operator[](int i);
  22. private:
  23. // 字符串长度 , 不包括 '\0'
  24. // 内存占用空间大小 = 字符串长度 + 1
  25. int m_len;
  26. // 字符串指针, 指向堆内存中的字符串
  27. char* m_p;
  28. };

2、String.cpp 类实现

  1. // 使用 strcpy 函数报错
  2. // error C4996: 'strcpy': This function or variable may be unsafe.
  3. // Consider using strcpy_s instead.
  4. // To disable deprecation, use _CRT_SECURE_NO_WARNINGS.
  5. // See online help for details.
  6. #define _CRT_SECURE_NO_WARNINGS
  7. #include "String.h"
  8. // 默认的无参构造函数
  9. String::String()
  10. {
  11. // 默认构造一个空字符串 , 字符串长度为 0
  12. // 但是 , 字符串指针 指向的内存空间大小是 1 , 内容是 '\0'
  13. m_len = 0;
  14. // 使用 new 关键字为 char* m_p; 指针分配内存
  15. // 对于基础数据类型 new 等同于 malloc
  16. m_p = new char[m_len + 1];
  17. // 拷贝空字符串到 m_p 指向的内存中
  18. strcpy(m_p, "");
  19. cout << "调用无参构造函数" << endl;
  20. }
  21. // 有参构造函数 , 接收一个 char* 类型字符串指针
  22. String::String(const char* p)
  23. {
  24. if (p == NULL)
  25. {
  26. // 默认构造一个空字符串 , 字符串长度为 0
  27. // 但是 , 字符串指针 指向的内存空间大小是 1 , 内容是 '\0'
  28. this->m_len = 0;
  29. // 使用 new 关键字为 char* m_p; 指针分配内存
  30. // 对于基础数据类型 new 等同于 malloc
  31. this->m_p = new char[this->m_len + 1];
  32. // 拷贝空字符串到 m_p 指向的内存中
  33. strcpy(m_p, "");
  34. }
  35. else
  36. {
  37. // 获取传入字符串的长度
  38. // 但是 , 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'
  39. this->m_len = strlen(p);
  40. // 使用 new 关键字为 char* m_p; 指针分配内存
  41. // 对于基础数据类型 new 等同于 malloc
  42. this->m_p = new char[this->m_len + 1];
  43. // 拷贝字符串到 m_p 指向的内存中
  44. strcpy(m_p, p);
  45. }
  46. cout << "调用有参构造函数" << endl;
  47. };
  48. // 拷贝构造函数 , 使用 String 对象初始化 对象值
  49. String::String(const String& s)
  50. {
  51. // 拷贝字符串长度
  52. // 注意 : 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'
  53. this->m_len = s.m_len;
  54. // 使用 new 关键字为 char* m_p; 指针分配内存
  55. // 对于基础数据类型 new 等同于 malloc
  56. this->m_p = new char[this->m_len + 1];
  57. // 拷贝字符串到 m_p 指向的内存中
  58. strcpy(this->m_p, s.m_p);
  59. cout << "调用拷贝构造函数" << endl;
  60. }
  61. // 析构函数
  62. String::~String()
  63. {
  64. if (this->m_p != NULL)
  65. {
  66. // 之前使用 new 分配的内存
  67. // 释放内存就需要使用 delete
  68. // 使用 malloc 分配的内存需要使用 free 释放
  69. delete[] this->m_p;
  70. // 设置指针指为空 , 避免出现野指针
  71. this->m_p = NULL;
  72. // 设置字符串长度为 0
  73. this->m_len = 0;
  74. }
  75. }
  76. // 重载等号 = 操作符 , 右操作数是 String 对象的情况
  77. String& String::operator=(const String& s)
  78. {
  79. // 先处理本对象已分配的内存
  80. if (this->m_p != NULL)
  81. {
  82. // 之前使用 new 分配的内存
  83. // 释放内存就需要使用 delete
  84. // 使用 malloc 分配的内存需要使用 free 释放
  85. delete[] this->m_p;
  86. // 设置指针指为空 , 避免出现野指针
  87. this->m_p = NULL;
  88. // 设置字符串长度为 0
  89. this->m_len = 0;
  90. }
  91. // 拷贝字符串长度
  92. // 注意 : 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'
  93. this->m_len = s.m_len;
  94. // 使用 new 关键字为 char* m_p; 指针分配内存
  95. // 对于基础数据类型 new 等同于 malloc
  96. this->m_p = new char[this->m_len + 1];
  97. // 拷贝字符串到 m_p 指向的内存中
  98. strcpy(this->m_p, s.m_p);
  99. cout << "调用重载 等号 = 操作符函数 String& String::operator=(const String& s)" << endl;
  100. return *this;
  101. }
  102. // 重载等号 = 操作符 , 右操作数是 字符串常量值 的情况
  103. String& String::operator=(const char* p)
  104. {
  105. // 先处理本对象已分配的内存
  106. if (this->m_p != NULL)
  107. {
  108. // 之前使用 new 分配的内存
  109. // 释放内存就需要使用 delete
  110. // 使用 malloc 分配的内存需要使用 free 释放
  111. delete[] this->m_p;
  112. // 设置指针指为空 , 避免出现野指针
  113. this->m_p = NULL;
  114. // 设置字符串长度为 0
  115. this->m_len = 0;
  116. }
  117. // 拷贝字符串长度
  118. // 注意 : 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'
  119. this->m_len = strlen(p);
  120. // 使用 new 关键字为 char* m_p; 指针分配内存
  121. // 对于基础数据类型 new 等同于 malloc
  122. this->m_p = new char[this->m_len + 1];
  123. // 拷贝字符串到 m_p 指向的内存中
  124. strcpy(this->m_p, p);
  125. cout << "调用重载 等号 = 操作符函数 String& String::operator=(const char* p)" << endl;
  126. return *this;
  127. }
  128. // 重载 数组下标 [] 操作符
  129. char& String::operator[](int i)
  130. {
  131. cout << "调用重载 下标 [] 操作符函数 char& String::operator[](int i)" << endl;
  132. // 直接返回对应 i 索引字符
  133. return this->m_p[i];
  134. }

3、Test.cpp 测试类

  1. #include "iostream"
  2. using namespace std;
  3. // 导入自定义的 String 类
  4. #include "String.h"
  5. int main() {
  6. // 调用无参构造函数
  7. String s1;
  8. // 调用有参构造函数
  9. String s2("Tom");
  10. // 调用拷贝构造函数
  11. String s3 = s2;
  12. // 调用重载的等号运算符函数, 右操作数是 String 对象
  13. s1 = s2;
  14. // 调用重载的等号运算符函数, 右操作数是 字符串常量值 , char* 指针类型
  15. s3 = "Jerry";
  16. // 调用重载的下标运算符函数
  17. char c = s3[3];
  18. // 控制台暂停 , 按任意键继续向后执行
  19. system("pause");
  20. return 0;
  21. }

4、执行结果

执行结果 :

  1. 调用无参构造函数
  2. 调用有参构造函数
  3. 调用拷贝构造函数
  4. 调用重载 等号 = 操作符函数 String& String::operator=(const String& s)
  5. 调用重载 等号 = 操作符函数 String& String::operator=(const char* p)
  6. 调用重载 下标 [] 操作符函数 char& String::operator[](int i)

在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,142人围观)

还没有评论,来说两句吧...

相关阅读