【C++】运算符重载案例 - 字符串类 ④ ( 重载 双等号 == 运算符 | 重载 不等号 != 运算符 | 代码示例 )

刺骨的言语ヽ痛彻心扉 2024-03-01 08:33 99阅读 0赞

文章目录

  • 一、重载 双等号 / 不等号 运算符
    • 1、等于判断 == 运算符重载
    • 2、重载 不等号 != 运算符
  • 三、完整代码示例
    • 1、String.h 类头文件
    • 2、String.cpp 类实现
    • 3、Test.cpp 测试类

一、重载 双等号 / 不等号 运算符


1、等于判断 == 运算符重载

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

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

    • 要对 String a , b 对象对比操作 , 使用 == 运算符 , 使用时用法为 a == b ;
    • 函数名是 operate== ;

    operate==

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

    • 要对 String a , b 对象对比操作 , 使用 == 运算符 , 使用时用法为 a == b ;
    • 左操作数 : 其中 左操作数 是 String a , 这里通过 this 指针调用 , 不需要声明在参数中 ;
    • 右操作数 : 右操作数 是 String b ; 该操作数需要声明在参数中 , 注意需要声明 引用类型 ;
    • 上述两个是对象类型 , 对象一般传入 指针 或 引用 , 这里传入引用类型 ;

    operator==(String & s)

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

    • 此处返回值是 bool 类型 , 返回 true 或者 false 布尔值即可 ;

    bool operator==(String& s)

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

    • 先对比数组的长度是否相等 ;
    • 然后对比数组中每个元素是否相等 ;

    // 重载 双等号 == 运算符
    bool String::operator==(String& s)
    {

    1. // 首先判断数组长度是否相等
    2. if (this->m_len != s.m_len)
    3. {
    4. return false;
    5. }
    6. for (size_t i = 0; i < this->m_len; i++)
    7. {
    8. // 只要有一个元素不相等, 整个数组就不相等
    9. if (this->m_p[i] != s.m_p[i])
    10. {
    11. return false;
    12. }
    13. }
    14. return true;

    }

2、重载 不等号 != 运算符

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

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

    • 要对 String a , b 对象对比操作 , 使用 != 运算符 , 使用时用法为 a != b ;
    • 函数名是 operate!= ;

    operate!=

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

    • 要对 String a , b 对象对比操作 , 使用 != 运算符 , 使用时用法为 a != b ;
    • 左操作数 : 其中 左操作数 是 String a , 这里通过 this 指针调用 , 不需要声明在参数中 ;
    • 右操作数 : 右操作数 是 String b ; 该操作数需要声明在参数中 , 注意需要声明 引用类型 ;
    • 上述两个是对象类型 , 对象一般传入 指针 或 引用 , 这里传入引用类型 ;

    operator!=(String& a)

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

    • 此处返回值是 bool 类型 , 返回 true 或者 false 布尔值即可 ;

    bool operator!=(String& s)

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

    • 先对比数组的长度是否不相等 ;
    • 然后对比数组中每个元素是否不相等 ;

    // 重载 不等号 != 运算符
    bool String::operator!=(String& s)
    {

    1. // 首先判断数组长度是否相等
    2. if (this->m_len != s.m_len)
    3. {
    4. return false;
    5. }
    6. for (size_t i = 0; i < this->m_len; i++)
    7. {
    8. // 只要有一个元素不相等, 整个数组就不相等
    9. if (this->m_p[i] != s.m_p[i])
    10. {
    11. return false;
    12. }
    13. }
    14. return true;

    }

三、完整代码示例


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. // 有参构造函数 , 接收 int 类型值 , 表示字符串大小
  12. String(int len);
  13. // 拷贝构造函数 , 使用 String 对象初始化 对象值
  14. String(const String& s);
  15. // 析构函数
  16. ~String();
  17. public:
  18. // 重载等号 = 操作符 , 右操作数是 String 对象的情况
  19. String& operator=(const String& s);
  20. // 重载等号 = 操作符 , 右操作数是 字符串常量值 的情况
  21. String& operator=(const char* p);
  22. // 重载 数组下标 [] 操作符
  23. char& operator[](int i);
  24. // 重载 双等号 == 运算符
  25. bool operator==(String& s);
  26. // 重载 不等号 != 运算符
  27. bool operator!=(String& s);
  28. // 使用 全局函数 实现 左移运算符 << 重载
  29. // 将全局函数 声明为 String 的友元函数
  30. friend ostream& operator<<(ostream& out, String& s);
  31. public:
  32. // 获取私有成员 char* m_p
  33. char* str();
  34. // 获取私有成员 int m_len
  35. int len();
  36. private:
  37. // 字符串长度 , 不包括 '\0'
  38. // 内存占用空间大小 = 字符串长度 + 1
  39. int m_len;
  40. // 字符串指针, 指向堆内存中的字符串
  41. char* m_p;
  42. };

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(this->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(this->m_p, p);
  45. }
  46. cout << "调用有参构造函数" << endl;
  47. }
  48. // 有参构造函数 , 接收 int 类型值 , 表示字符串大小
  49. String::String(int len)
  50. {
  51. if (len == 0)
  52. {
  53. // 默认构造一个空字符串 , 字符串长度为 0
  54. // 但是 , 字符串指针 指向的内存空间大小是 1 , 内容是 '\0'
  55. this->m_len = 0;
  56. // 使用 new 关键字为 char* m_p; 指针分配内存
  57. // 对于基础数据类型 new 等同于 malloc
  58. this->m_p = new char[this->m_len + 1];
  59. // 拷贝空字符串到 m_p 指向的内存中
  60. strcpy(this->m_p, "");
  61. }
  62. else
  63. {
  64. // 获取传入字符串的长度
  65. // 但是 , 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'
  66. this->m_len = len;
  67. // 使用 new 关键字为 char* m_p; 指针分配内存
  68. // 对于基础数据类型 new 等同于 malloc
  69. this->m_p = new char[this->m_len + 1];
  70. // 将内存空间设置为 0 内容
  71. memset(this->m_p, 0, this->m_len);
  72. }
  73. };
  74. // 拷贝构造函数 , 使用 String 对象初始化 对象值
  75. String::String(const String& s)
  76. {
  77. // 拷贝字符串长度
  78. // 注意 : 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'
  79. this->m_len = s.m_len;
  80. // 使用 new 关键字为 char* m_p; 指针分配内存
  81. // 对于基础数据类型 new 等同于 malloc
  82. this->m_p = new char[this->m_len + 1];
  83. // 拷贝字符串到 m_p 指向的内存中
  84. strcpy(this->m_p, s.m_p);
  85. cout << "调用拷贝构造函数" << endl;
  86. }
  87. // 析构函数
  88. String::~String()
  89. {
  90. if (this->m_p != NULL)
  91. {
  92. // 之前使用 new 分配的内存
  93. // 释放内存就需要使用 delete
  94. // 使用 malloc 分配的内存需要使用 free 释放
  95. delete[] this->m_p;
  96. // 设置指针指为空 , 避免出现野指针
  97. this->m_p = NULL;
  98. // 设置字符串长度为 0
  99. this->m_len = 0;
  100. }
  101. }
  102. // 重载等号 = 操作符 , 右操作数是 String 对象的情况
  103. String& String::operator=(const String& s)
  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 = s.m_len;
  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, s.m_p);
  125. cout << "调用重载 等号 = 操作符函数 String& String::operator=(const String& s)" << endl;
  126. return *this;
  127. }
  128. // 重载等号 = 操作符 , 右操作数是 字符串常量值 的情况
  129. String& String::operator=(const char* p)
  130. {
  131. // 先处理本对象已分配的内存
  132. if (this->m_p != NULL)
  133. {
  134. // 之前使用 new 分配的内存
  135. // 释放内存就需要使用 delete
  136. // 使用 malloc 分配的内存需要使用 free 释放
  137. delete[] this->m_p;
  138. // 设置指针指为空 , 避免出现野指针
  139. this->m_p = NULL;
  140. // 设置字符串长度为 0
  141. this->m_len = 0;
  142. }
  143. // 拷贝字符串长度
  144. // 注意 : 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'
  145. this->m_len = strlen(p);
  146. // 使用 new 关键字为 char* m_p; 指针分配内存
  147. // 对于基础数据类型 new 等同于 malloc
  148. this->m_p = new char[this->m_len + 1];
  149. // 拷贝字符串到 m_p 指向的内存中
  150. strcpy(this->m_p, p);
  151. cout << "调用重载 等号 = 操作符函数 String& String::operator=(const char* p)" << endl;
  152. return *this;
  153. }
  154. // 重载 数组下标 [] 操作符
  155. char& String::operator[](int i)
  156. {
  157. cout << "调用重载 下标 [] 操作符函数 char& String::operator[](int i)" << endl;
  158. // 直接返回对应 i 索引字符
  159. return this->m_p[i];
  160. }
  161. // 重载 双等号 == 运算符
  162. bool String::operator==(String& s)
  163. {
  164. // 首先判断数组长度是否相等
  165. if (this->m_len != s.m_len)
  166. {
  167. return false;
  168. }
  169. for (size_t i = 0; i < this->m_len; i++)
  170. {
  171. // 只要有一个元素不相等, 整个数组就不相等
  172. if (this->m_p[i] != s.m_p[i])
  173. {
  174. return false;
  175. }
  176. }
  177. return true;
  178. }
  179. // 重载 不等号 != 运算符
  180. bool String::operator!=(String& s)
  181. {
  182. // 首先判断数组长度是否相等
  183. if (this->m_len != s.m_len)
  184. {
  185. return false;
  186. }
  187. for (size_t i = 0; i < this->m_len; i++)
  188. {
  189. // 只要有一个元素不相等, 整个数组就不相等
  190. if (this->m_p[i] != s.m_p[i])
  191. {
  192. return false;
  193. }
  194. }
  195. return true;
  196. }
  197. // 获取私有成员 char* m_p
  198. char* String::str()
  199. {
  200. return this->m_p;
  201. }
  202. // 获取私有成员 int m_len
  203. int String::len()
  204. {
  205. return this->m_len;
  206. }
  207. // 全局函数 中实现 String 左移运算符重载
  208. // 返回 ostream& 引用类型 , 是为了支持链式调用 cout << s1 << endl;
  209. ostream& operator<<(ostream& out, String& s)
  210. {
  211. cout << "调用重载 左移 << 操作符函数 ostream& operator<<(ostream& out, String& s)" << endl;
  212. // 在函数体中将 String 对象的 m_p 指针指向的数据输出到 out 输出流中
  213. out << s.m_p << endl;
  214. // 该返回值还需要当左值使用
  215. return out;
  216. }

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. cout << s3 << endl;
  20. // 控制台暂停 , 按任意键继续向后执行
  21. system("pause");
  22. return 0;
  23. }

发表评论

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

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

相关阅读