• C++零碎记录(八)


    14. 运算符重载简介

    14.1 运算符重载简介

    ① 运算符重载:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。

    ② 对于内置的数据类型的表达式的运算符是不可能改变的。

    14.2 加号运算符重载

    ① 加号运算符作用:实现两个自定义数据类型相加的运算。

    1. #include <iostream>
    2. using namespace std;
    3. //加号运算符重载
    4. class Person
    5. {
    6. public:
    7. //1、成员函数重载+
    8. Person operator+(Person& p)
    9. {
    10. Person temp;
    11. temp.m_A = this->m_A + p.m_A;
    12. temp.m_B = this->m_B + p.m_B;
    13. return temp;
    14. }
    15. int m_A;
    16. int m_B;
    17. };
    18. /*
    19. //全局函数重载+
    20. Person operator+(Person &p1, Person &p2)
    21. {
    22. Person temp;
    23. temp.m_A = p1.m_A + p2.m_A;
    24. temp.m_B = p1.m_B + p2.m_B;
    25. return temp;
    26. }
    27. */
    28. //函数重载的版本
    29. Person operator+(Person& p1, int num)
    30. {
    31. Person temp;
    32. temp.m_A = p1.m_A + num;
    33. temp.m_B = p1.m_B + num;
    34. return temp;
    35. }
    36. void test01()
    37. {
    38. Person p1;
    39. p1.m_A = 10;
    40. p1.m_B = 10;
    41. Person p2;
    42. p2.m_A = 10;
    43. p2.m_B = 10;
    44. //成员函数重载本质调用
    45. //Person p3 = p1.operator+(p2);
    46. //全局函数重载本质调用
    47. //Person p3 = operator+(p1,p2);
    48. Person p3 = p1 + p2; //重载本质被简化后的形式
    49. //运算符重载,也可以发生函数重载
    50. Person p4 = p1 + 10; //Person + int
    51. cout << "p3.m_A:" << p3.m_A << endl;
    52. cout << "p3.m_B:" << p3.m_B << endl;
    53. cout << "p4.m_A:" << p4.m_A << endl;
    54. cout << "p4.m_B:" << p4.m_B << endl;
    55. }
    56. int main()
    57. {
    58. test01();
    59. system("pause");
    60. return 0;
    61. }

    运行结果:

    • p3.m_A:20
    • p3.m_B:20
    • p4.m_A:20
    • p4.m_B:20
    • 请按任意键继续. . .

    14.3 左移运算符重载

    ① 左移运算符重载:可以输出自定义数据类型。

    ② 重载左移运算符配合友元可以实现自定义数据类型。

    1. #include
    2. using namespace std;
    3. //左移运算符
    4. class Person
    5. {
    6. friend ostream& operator<<(ostream& out, Person& p);
    7. public:
    8. Person(int a, int b)
    9. {
    10. m_A = a;
    11. m_B = b;
    12. }
    13. /*
    14. //利用成员函数重载 左移运算符 p.operator<<(cout) 简化版本 p << cout
    15. //成员函数不能利用重载<<运算符,因为无法实现cout在左侧
    16. //当不知道返回值是什么类型的时候,可以先写个void,以后再改
    17. void operator<<(Person& p)
    18. {
    19. }
    20. */
    21. private:
    22. int m_A;
    23. int m_B;
    24. };
    25. //只能利用全局函数重载左移运算符
    26. //如果返回类型为void,那么就无法无限追加,也没有办法在后面添加换行符
    27. ostream & operator<<(ostream &cout, Person &p) //本质 operator << (cout , p) , 简化 cout << p
    28. //cout是别名,这里可以取out、kn...
    29. //cout为ostream输出流数据类型
    30. {
    31. cout << "m_A= " << p.m_A << " m_B=" << p.m_B;
    32. return cout;
    33. }
    34. void test01()
    35. {
    36. Person p(10,10);
    37. cout << p << " hello world" << endl;
    38. }
    39. int main()
    40. {
    41. test01();
    42. system("pause");
    43. return 0;
    44. }

    运行结果:

    • m_A= 10 m_B=10 hello world
    • 请按任意键继续. . .

    14.4 递增运算符

    ① 递增运算符重载:通过重载递增运算符,实现自己的整型数据。

    ② 前置递增返回的是引用,后置递增返回的是值。

    1. #include
    2. using namespace std;
    3. //重载递增运算符
    4. class MyInteger
    5. {
    6. friend ostream& operator<<(ostream& cout, MyInteger myint);
    7. public:
    8. MyInteger()
    9. {
    10. m_Num = 0;
    11. }
    12. //重载前置++运算符,返回引用是为了一直对一个数据进行递增操作,而返回值并不是一直对一个数据进行递增操作
    13. MyInteger& operator++()
    14. {
    15. //先进行++运算
    16. m_Num++;
    17. //再将自身做一个返回
    18. return *this; //把自身做一个返回
    19. }
    20. //重载后置++运算符 int代表占位参数,可以用于区分前置和后置递增
    21. //后置递增不能返回引用,因为temp是局部变量,如果返回temp,当程序运行完后变量就释放了,再调用temp就是非法操作了
    22. MyInteger operator++(int)
    23. {
    24. //先记录当时结果
    25. MyInteger temp = *this;
    26. //后 递增
    27. m_Num++;
    28. //最后将记录结果做返回
    29. return temp;
    30. }
    31. private:
    32. int m_Num;
    33. };
    34. //只能利用全局函数重载左移运算符
    35. ostream & operator<<(ostream &cout, MyInteger myint) //本质 operator << (cout , p) , 简化 cout << p
    36. //cout是别名,这里可以取out、kn...
    37. //cout为ostream输出流数据类型
    38. {
    39. cout << myint.m_Num;
    40. return cout;
    41. }
    42. void test01()
    43. {
    44. MyInteger myint;
    45. cout << ++(++myint) << endl;
    46. cout << myint << endl;
    47. }
    48. void test02()
    49. {
    50. MyInteger myint;
    51. cout << myint++ << endl;
    52. cout << myint << endl;
    53. }
    54. int main()
    55. {
    56. test01();
    57. test02();
    58. /*
    59. int a = 0;
    60. cout << ++(++a) << endl; //运行结果为2
    61. cout << a << endl; //运行结果为2,表示一直对一个数据进行递增
    62. */
    63. system("pause");
    64. return 0;
    65. }

    运行结果:

    • 2
    • 2
    • 0
    • 1
    • 请按任意键继续. . .

    14.5 赋值运算符

    ① C++编译器至少给一个类添加4个函数:

    1. 默认构造函数(无参,函数体为空)
    2. 默认析构函数(无参,函数体为空)
    3. 默认拷贝构造函数,对属性进行值拷贝
    4. 赋值运算符operator=,对属性进行值拷贝
    5. 如果类中有属性指向堆区,做赋值操作时也会出现浅拷贝问题。
    1. #include
    2. using namespace std;
    3. //重载赋值运算符
    4. class Person
    5. {
    6. public:
    7. Person(int age)
    8. {
    9. m_Age = new int(age);
    10. }
    11. ~Person()
    12. {
    13. if (m_Age != NULL)
    14. {
    15. delete m_Age;
    16. m_Age = NULL;
    17. }
    18. }
    19. //重载 赋值运算符
    20. //如果返回的是值,而不是引用,是创建一个拷贝函数,返回的是一个副本,而不是自身
    21. Person& operator=(Person& p)
    22. {
    23. //编译器默认是提供浅拷贝
    24. //m_Age = p.m_Age;
    25. //浅拷贝带来的问题是,当创建数据在堆区时,析构代码导致内存重复释放,报错
    26. //应该先判断是否有属性在堆区,如果有先释放干净,然后再深拷贝
    27. if (m_Age != NULL)
    28. {
    29. delete m_Age;
    30. m_Age = NULL;
    31. }
    32. //深拷贝
    33. m_Age = new int(*p.m_Age);
    34. //返回对象本身
    35. return *this;
    36. }
    37. int *m_Age;
    38. };
    39. void test01()
    40. {
    41. Person p1(18);
    42. Person p2(20);
    43. Person p3(23);
    44. p3 = p2 = p1; //赋值操作
    45. cout << "p1的年龄为:" << *p1.m_Age << endl;
    46. cout << "p2的年龄为:" << *p2.m_Age << endl;
    47. cout << "p3的年龄为:" << *p3.m_Age << endl;
    48. }
    49. int main()
    50. {
    51. test01();
    52. /*
    53. int a = 10;
    54. int b = 20;
    55. int c = 30;
    56. c = b = a;
    57. cout << "a= " << a << endl;
    58. cout << "b= " << b << endl;
    59. cout << "c= " << c << endl;
    60. */
    61. system("pause");
    62. return 0;
    63. }

    运行结果:

    • p1的年龄为:18
    • p2的年龄为:18
    • p3的年龄为:18
    • 请按任意键继续. . .

    14.6 关系重载运算符

    1. #include
    2. using namespace std;
    3. #include
    4. //重载关系运算符
    5. class Person
    6. {
    7. public:
    8. Person(string name, int age)
    9. {
    10. m_Name = name;
    11. m_Age = age;
    12. }
    13. //重载 == 号
    14. bool operator==(Person& p)
    15. {
    16. if (this->m_Name == p.m_Name && this->m_Age == p.m_Age)
    17. {
    18. return true;
    19. }
    20. return false;
    21. }
    22. bool operator!=(Person& p)
    23. {
    24. if (this->m_Name != p.m_Name && this->m_Age != p.m_Age)
    25. {
    26. return true;
    27. }
    28. return false;
    29. }
    30. string m_Name;
    31. int m_Age;
    32. };
    33. void test01()
    34. {
    35. Person p1("Tom", 17);
    36. Person p2("Jerry", 18);
    37. if (p1 == p2)
    38. {
    39. cout << "p1和p2是相等的!" << endl;
    40. }
    41. else
    42. {
    43. cout << "p1和p2是不相等的!" << endl;
    44. }
    45. if (p1 != p2)
    46. {
    47. cout << "p1和p2是不相等的!" << endl;
    48. }
    49. else
    50. {
    51. cout << "p1和p2是相等的!" << endl;
    52. }
    53. }
    54. int main()
    55. {
    56. test01();
    57. system("pause");
    58. return 0;
    59. }

    运行结果:

    • p1和p2是不相等的!
    • p1和p2是不相等的!
    • 请按任意键继续. . .

    14.7 函数调用运算符重载

    ① 函数调用运算符()也可以重载。

    ② 由于重载后使用的方式非常像函数的调用,因此称为仿函数

    ③ 仿函数没有固定写法,非常灵活。

    1. #include
    2. using namespace std;
    3. #include
    4. //函数调用运算符重载
    5. //打印输出类
    6. class MyPrint
    7. {
    8. public:
    9. //重载函数调用运算符
    10. void operator()(string test)
    11. {
    12. cout << test << endl;
    13. }
    14. };
    15. //正常函数
    16. void MyPrint02(string test)
    17. {
    18. cout << test << endl;
    19. }
    20. void test01()
    21. {
    22. MyPrint myPrint;
    23. myPrint("hello world");
    24. }
    25. //仿函数非常灵活,没有固定的写法
    26. //加法类
    27. class MyAdd
    28. {
    29. public:
    30. int operator()(int num1, int num2)
    31. {
    32. return num1 + num2;
    33. }
    34. };
    35. void test02()
    36. {
    37. MyAdd myadd;
    38. int ret = myadd(100,100);
    39. cout << "ret = " << ret << endl;
    40. //匿名函数对象
    41. cout << MyAdd()(100, 100) << endl;
    42. // MyAdd()为创建一个匿名对象,匿名对象的特点为当前行执行完立即释放
    43. }
    44. int main()
    45. {
    46. test01();
    47. MyPrint02("hello world"); //由于使用起来非常类似于函数调用,因此称为仿函数
    48. test02();
    49. system("pause");
    50. return 0;
    51. }

    运行结果:

    • hello world
    • hello world
    • ret = 200
    • 200
    • 请按任意键继续. . .

    链接:https://www.zhihu.com/question/437657370/answer/1692846096

  • 相关阅读:
    Es集群部署
    Dextran-ALK,葡聚糖-炔基|炔基修饰葡聚糖,葡萄糖/乳糖基/黄原胶/岩藻多糖/木聚糖
    【2024年最新】NodeMCU-ESP8266刷AT固件教程——适用于esp-12E和esp-12F
    电梯物联网之梯控相机方案-防止电瓶车进电梯
    python数学建模--线性规划问题案例及求解
    JSP EL表达式的基本语法及运算符的优先级(一览表)
    【Linux系统管理】09 文件系统管理 & 高级文件系统管理
    Android Studio实现一个点餐系统
    Spring Data JPA 之 DataSource 详解及其加载过程
    mysql数据库优化之数据库非sql优化
  • 原文地址:https://blog.csdn.net/qq18218628646/article/details/132733463