• C++核心编程——P39~P44-运算符重载


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

    1.加号运算符重载

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

    例如:两个整型相加编译器知道该怎么进行运算,如果是两个自定义出来的类型,两个Person想加,编译器就不知道该怎么运算了。

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

    总结

    1. 对于内置的数据类型的表达式的运算符是不可能改变的//如int double,自定义的数据类型可以
    2. 不要滥用运算符重载

    2.左移运算符重载

    作用:可以输出自定义的类型

    1. #include
    2. using namespace std;
    3. class Person
    4. {
    5. friend ostream& operator<<(ostream& cout, Person& p);
    6. public:
    7. Person(int a, int b)
    8. {
    9. m_A = a;
    10. m_B = b;
    11. }
    12. //利用成员函数重载左移运算符p.operator<<(cout)简化版本p<
    13. //一般我们不会利用成员函数来重载<<运算符,以为无法实现cout在左边
    14. /*void operator<<(ostream &cout,Person &p)
    15. {
    16. cout << p.m_A << endl;
    17. cout << p.m_B << endl;
    18. }*/
    19. private:
    20. int m_A;
    21. int m_B;
    22. };
    23. //只能利用全局函数来重载左移运算符
    24. ostream& operator<<(ostream &cout, Person &p) //这样写的本质就是operator<<(cout,p)简化版本就是cout<
    25. {
    26. cout << p.m_A << endl;
    27. cout << p.m_B << endl;
    28. return cout;//cout是ostream类型
    29. }
    30. void test()
    31. {
    32. Person p(10,10);
    33. cout << p << "hello world" << endl;
    34. }
    35. int main(void)
    36. {
    37. test();
    38. system("pause");
    39. return 0;
    40. }

    3.递增运算符重载

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

    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. //返回引用是为了一直对一个数据进行递增操作
    14. MyInteger& operator++()//返回引用
    15. {
    16. ++m_Num;
    17. return *this;//this是指向自身
    18. }
    19. //重载++运算符——后置
    20. //返回值不同不能作为函数重载的条件
    21. MyInteger operator++(int)//这个int在这里作为占位参数,用来区分前置递增和后置递增
    22. {
    23. //先 记录当时结果
    24. MyInteger temp = *this;
    25. //后 递增
    26. m_Num++;
    27. //最后 返回
    28. return temp;
    29. //后置递增要返回值,因为如果返回引用,这里相当于返回的是一个局部对象的引用。
    30. //局部对象在当前函数执行完毕之后就被释放掉了,还要返回引用就是非法操作。
    31. }
    32. private:
    33. int m_Num;
    34. };
    35. //全局函数重载左移运算符
    36. ostream& operator<<(ostream& cout, MyInteger myint)
    37. {
    38. cout << myint.m_Num << endl;
    39. return cout;
    40. }
    41. void test()
    42. {
    43. MyInteger myint;
    44. cout << ++(++myint);
    45. cout <
    46. }
    47. void test02()
    48. {
    49. MyInteger myint;
    50. cout << myint++ << endl;
    51. cout << myint << endl;
    52. }
    53. int main(void)
    54. {
    55. //test();
    56. test02();
    57. system("pause");
    58. return 0;
    59. }

    总结:前置递增返回引用,后置递增返回值。

    4.赋值运算符重载

    C++编译器至少给一个类添加4个函数(前三个之前已经讲过了)

    1. 默认构造函数(无参,函数体为空)
    2. 默认析构函数(无参,函数体为空)
    3. 默认拷贝构造函数,对属性进行值拷贝
    4. 赋值运算符operator=,对属性进行值拷贝

     如果类中有属性指向堆区,做赋值操作时也会出现深浅拷贝问题。

    1. #include
    2. using namespace std;
    3. class Person
    4. {
    5. public:
    6. Person(int age)
    7. {
    8. m_Age = new int(age);
    9. }
    10. ~Person()
    11. {
    12. if (m_Age != NULL)
    13. {
    14. delete m_Age;
    15. m_Age = NULL;
    16. }
    17. }
    18. //重载赋值运算符
    19. Person& operator=(Person &p)
    20. {
    21. //编译器默认提供的是浅拷贝操作//m_Age = p.m_Age;
    22. //应该先判断是否有属性在堆区,如果有先释放干净,然后再深拷贝。
    23. if (m_Age != NULL)
    24. {
    25. delete m_Age;
    26. m_Age = NULL;
    27. }
    28. //深拷贝操作
    29. m_Age = new int(*p.m_Age);
    30. //指回自身的指针是this指针,返回对象本身
    31. return *this;
    32. }
    33. int *m_Age;
    34. };
    35. void test1()
    36. {
    37. Person p1(18);
    38. Person p2(20);
    39. Person p3(30);
    40. p3 = p2 = p1;
    41. cout << *(p1.m_Age) << endl;
    42. cout << *(p2.m_Age) << endl;
    43. cout << *(p3.m_Age) << endl;
    44. //三个人都是18
    45. }
    46. int main(void)
    47. {
    48. test1();
    49. system("pause");
    50. return 0;
    51. }

    5.关系运算符重载

    作用:重载关系运算符,可以让两个自定义类型对象进行对比操作

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

    //内置数据类型可以比对,但是自定义类型不行如:person这个数据类型

    6.函数调用运算符重载

    • 函数调用运算符()也可以重载
    • 由于重载后使用的方式非常像函数的调用,因此称为仿函数
    • 仿函数没有固定写法,非常灵活
    1. #include
    2. #include
    3. using namespace std;
    4. //函数调用运算符重载
    5. class MyPrint
    6. {
    7. public:
    8. //重载函数调用运算符
    9. void operator()(string text)
    10. {
    11. cout << text << endl;
    12. }
    13. };
    14. //仿函数非常灵活,没有固定的写法
    15. //加法类
    16. class MyAdd
    17. {
    18. public:
    19. int operator()(int a, int b)
    20. {
    21. return a + b;
    22. }
    23. };
    24. void test()
    25. {
    26. MyPrint myprint;
    27. myprint("hello world");//这里myprint是上一行代码 MyPrint myprint;中的对象myprint
    28. //()是重载的东西 //重载后使用的方式非常像函数的调用,因此称为仿函数
    29. MyAdd myadd;
    30. cout << myadd(1, 2) << endl;
    31. //匿名函数对象 特点:当前行被执行完立即释放
    32. cout << MyAdd()(100,100) << endl;
    33. }
    34. void test02()
    35. {
    36. MyAdd myadd;
    37. int ret = myadd(100, 100);
    38. cout <<"ret="<
    39. }
    40. int main(void)
    41. {
    42. test();
    43. test02();
    44. system("pause");
    45. return 0;
    46. }

  • 相关阅读:
    Stream常用操作以及原理探索
    Java Web 7 JavaScript 7.6 DOM
    Python——弹幕词频统计及其文本分析(绘制词云)(含源代码)
    计算机网络:数据链路层功能
    Autofac 注入仓储模式
    Android自定义控件(五) 自定义View实现Android Loading效果
    Java中的线程等待和唤醒、线程死锁、常用的线程池类(多线程下篇含线程池的使用及原理)
    【国外翻译】采访漫威视觉开发总监:AndyPark
    SveletJs学习——简介模块
    Linux的介绍和安装
  • 原文地址:https://blog.csdn.net/LDBH66/article/details/133099498