• c++运算符重载


    目录

    运算符重载的基本概念

    重载加号运算符(+)

    类内实现

    类外实现

    运算符重载碰上友元函数

    可重载和不可重载的运算符

    可重载的运算符

    不可重载的运算符

    重载自加自减运算符(a++ ++a)

    智能指针

    重载等号运算符(=)

    重载等于和不等运算符(==  !=)


    运算符重载的基本概念

    概念:

    运算符重载与函数重载比较类似,相当于让一个运算符具有另外一种含义;

    语法:

    定义重载的运算符就像定义函数,只是该函数的名字是 operator@,这里的@代表了被重载的运算符。函数的参数中参数个数取决于两个因素。运算符是一元(一个参数)的还是二元(两个参数);运算符被定义为全局函数(对于一元是一个参数,对于二元是两个参数)还是成员函数(对于一元没有参数,对于二元是一个参数-此时该类的对象用作左耳参数)

    重载加号运算符(+)

    类内实现

    1. #include
    2. using namespace std;
    3. class person
    4. {
    5. public:
    6. person(int age)
    7. {
    8. this->age = age;
    9. }
    10. person operator+(person &p2)//
    11. {
    12. person p = (this->age+p2.age);
    13. return p;
    14. }
    15. int age;
    16. };
    17. void test01()
    18. {
    19. person p1(10);
    20. person p2(20);
    21. person p3 = p1 + p2;
    22. cout << p3.age << endl;
    23. }
    24. int main()
    25. {
    26. test01();
    27. return 0;
    28. }

    类外实现

    1. #include
    2. using namespace std;
    3. class person
    4. {
    5. public:
    6. person(int age)
    7. {
    8. this->age = age;
    9. }
    10. int age;
    11. };
    12. person operator+(person &p1,person &p2)//
    13. {
    14. person p = (p1.age+p2.age);
    15. return p;
    16. }
    17. void test01()
    18. {
    19. person p1(10);
    20. person p2(20);
    21. person p3 = p1 + p2;
    22. cout << p3.age << endl;
    23. }
    24. int main()
    25. {
    26. test01();
    27. return 0;
    28. }

    运算符重载碰上友元函数

    左移运算符的重载函数声明为类的友元函数 就可以访问类的成员

    1. #include
    2. using namespace std;
    3. class person
    4. {
    5. friend ostream & operator<<(ostream &cout,person &p);
    6. public:
    7. person(int age)
    8. {
    9. this->age = age;
    10. }
    11. private:
    12. int age;
    13. };
    14. ostream & operator<<(ostream &cout,person &p)
    15. {
    16. cout << p.age;
    17. return cout;
    18. }
    19. void test01()
    20. {
    21. person p1(10);
    22. cout << p1 << endl;
    23. }
    24. int main()
    25. {
    26. test01();
    27. return 0;
    28. }

    可重载和不可重载的运算符

    几乎c 中所有的运算符都可以重载,但运算符重载的使用时相当受限制的。特别是不能使用c 中当前没有意义的 运算符( 例如用 ** 求幂 ) 不能改变运算符优先级,不能改变运算符的参数个数。这样的限制有意义,否则,所有这些行为产生的运算符只会混淆而不是澄清寓语意。

    可重载的运算符

    不可重载的运算符

    重载自加自减运算符(a++ ++a)

    a++是先把a赋值到一个临时空间,再对a+1赋值给临时变量,等运算结束后才返回临时变量给a  (参与运算的是自加之前的值)

    ++a是先给a+1,直接对a赋值,不需要开辟临时空间(参与运算的是返回值的引用)

    前置++返回的是引用

    后置++返回的是对象

    前置++调用void operator++()

    后置++调用myint operator++(int) 后置++多了一个占位参数

    1. #include
    2. using namespace std;
    3. class myint
    4. {
    5. public:
    6. myint &operator++()
    7. {
    8. this->num = this->num+1;
    9. return *this;
    10. }
    11. myint(int num)
    12. {
    13. this->num = num;
    14. }
    15. myint operator++(int)
    16. {
    17. myint tmp = *this;
    18. this->num = this->num+1;
    19. return tmp;
    20. }
    21. int num;
    22. };
    23. ostream &operator<<(ostream& cout,myint &p)
    24. {
    25. cout << p.num;
    26. return cout;
    27. }#include
    28. using namespace std;
    29. class myint
    30. {
    31. public:
    32. myint &operator++()
    33. {
    34. this->num = this->num+1;
    35. return *this;
    36. }
    37. myint(int num)
    38. {
    39. this->num = num;
    40. }
    41. myint operator++(int)
    42. {
    43. myint tmp = *this;
    44. this->num = this->num+1;
    45. return tmp;
    46. }
    47. int num;
    48. };
    49. ostream &operator<<(ostream& cout,myint &p)
    50. {
    51. cout << p.num;
    52. return cout;
    53. }
    54. void test01()
    55. {
    56. myint p1(10);
    57. cout << p1 << endl;
    58. ++p1;//调用operator++(p1)或者p1.operator()
    59. cout << ++p1 << endl;
    60. p1++;
    61. //cout << p1++ << end; //有些编译器会报错
    62. cout << p1 << endl;
    63. }
    64. int main()
    65. {
    66. test01();
    67. return 0;
    68. }

    智能指针

    我们经常new出一个对象,忘记释放,所以我们使用智能指针来维护

    智能指针实质上是一个局部对象 这个局部对象维护了new出来的对象的地址,在局部对象的析构函数中,会帮忙释放new出来的对象

    对于智能指针我们重载了->和* 让智能指针和普通指针一样使用

    1. #include
    2. using namespace std;
    3. class person
    4. {
    5. public:
    6. person(int age )
    7. {
    8. this->age = age;
    9. }
    10. int age;
    11. };
    12. class SmartPointer
    13. {
    14. public:
    15. SmartPointer(person *p1)
    16. {
    17. this->p = p1;
    18. }
    19. ~SmartPointer()
    20. {
    21. delete p;
    22. cout << "释放了p" << endl;
    23. }
    24. person *p;
    25. };
    26. void test01()
    27. {
    28. //局部对象 在释放之前可以帮助释放p
    29. person *p = new person(10);
    30. SmartPointer s1(p);
    31. cout << p->age <
    32. cout <<
    33. }
    34. int main()
    35. {
    36. test01();
    37. return 0;
    38. }

    重载等号运算符(=)

    编译器默认给每个类加上了四个函数

            默认的无参构造

            默认的拷贝构造

            析构函数

            operator=()

    1. #include
    2. #include
    3. using namespace std;
    4. class person
    5. {
    6. public:
    7. person()
    8. {
    9. }
    10. person(int agel,char *namel)
    11. {
    12. age = agel;
    13. name = new char[strlen(namel)+1];
    14. strcpy(name,namel);
    15. }
    16. person& operator=(person &p1)
    17. {
    18. this->age = p1.age;
    19. this->name = new char[strlen(p1.name)+1];
    20. strcpy(this->name,p1.name);
    21. return *this;//返回p2 为什么不返回p1?可以连续赋值 p3 = p2 = p1
    22. }
    23. ~person()
    24. {
    25. delete []name;
    26. }
    27. int age;
    28. char *name;
    29. };
    30. void test01()
    31. {
    32. person p1(10,(char *)"bob");
    33. person p2;
    34. p2 = p1;//p2.operator(person &p1)
    35. cout << p2.age << " " << p2.name <
    36. }
    37. int main()
    38. {
    39. test01();
    40. return 0;
    41. }

    重载等于和不等运算符(==  !=)

    1. #include
    2. #include
    3. using namespace std;
    4. class person
    5. {
    6. public:
    7. person()
    8. {
    9. }
    10. bool operator==(person &p2)
    11. {
    12. return this->age == p2.age && this->name == p2.name;
    13. }
    14. bool operator!=(person &p2)
    15. {
    16. return this->age != p2.age || this->name != p2.name;
    17. }
    18. person(int age,string name)
    19. {
    20. this->age = age;
    21. this->name = name;
    22. }
    23. int age;
    24. string name;
    25. };
    26. void test01()
    27. {
    28. person p1(10,"lucy");
    29. person p2(10,"bob");
    30. if(p1 == p2)
    31. {
    32. cout << "p1 = p2" << endl;
    33. }
    34. if(p1 != p2)
    35. {
    36. cout << "p1 != p2" << endl;
    37. }
    38. }
    39. int main()
    40. {
    41. test01();
    42. return 0;
    43. }

    函数调用符号()重载

    一个类中重载了()的类,那么类的定义出来的对象可以像函数一样使用,本质是调用了operator()这个函数

    1. #include
    2. #include
    3. using namespace std;
    4. class Myadd
    5. {
    6. public:
    7. int add(int a,int b)
    8. {
    9. return a + b;
    10. }
    11. int operator()(int x,int y)
    12. {
    13. return x + y;
    14. }
    15. };
    16. void test01()
    17. {
    18. Myadd p;
    19. cout << p.add(3,5) << endl;
    20. //p() 可以像函数一样调用的对象 函数对象
    21. cout << p(3,4) << endl;//p.operator()(3,4)
    22. cout << Myadd()(3,4) << endl;//定义一个匿名对象 Myadd().operator()(3,4)
    23. }
    24. int main()
    25. {
    26. test01();
    27. return 0;
    28. }

    尽量不要重载 || &&

    不能重载 operator&& operator|| 的原因是,无法在这两种情况下实现内置操作符的完整语义。说得更具体一 些,内置版本版本特殊之处在于:内置版本的&& || 首先计算左边的表达式,如果这完全能够决定结果,就无需计算右边的表达式了-- 而且能够保证不需要。我们都已经习惯这种方便的特性了。 我们说操作符重载其实是另一种形式的函数调用而已,对于函数调用总是在函数执行之前对所有参数进行求值。
    class Complex{
    public :
            Complex( int flag)
            {
                    this ->flag = flag;
            }
            Complex& operator +=(Complex& complex)
            {
                    this ->flag = this ->flag + complex.flag;
                    return * this ;
            }
            bool operator &&(Complex& complex)
            {
                    return this ->flag && complex.flag;
            }
    public :
            int flag;
    };
    int main(){
            Complex complex1( 0 ); //flag 0
            Complex complex2( 1 ); //flag 1
            //原来情况,应该从左往右运算,左边为假,则退出运算,结果为假
            //这边却是,先运算( complex1+complex2 ),导致, complex1 flag 变为         complex1+complex2 的值,complex1.a = 1
            // 1 && 1
            //complex1.operator&&(complex1.operator+=(complex2))
            if (complex1 && (complex1 += complex2))
            {
                    //complex1.operator+=(complex2)
                    cout << " !" << endl;
            }
            else {
                    cout << " !" << endl;
            }
            return EXIT_SUCCESS;
    }

    符号重载总结

    1.=, [], () -> 操作符只能通过成员函数进行重载
            例如 :p = 3 成员函数实现 p.operator=(3) 全局函数实现 operator(3,p) 如果把3写在左边 相当于 3 = p,将p赋值给3,但3是一个常量,常量不能作为左值
                   
    2.<< >> 只能通过全局函数配合友元函数进行重载
            例如:cout << p 因为要把cout放在操作符的左侧 不可能去修改标准库中的类 所以必须配合全局函数和友元函数进行重载
    3.不要重载 && || 操作符,因为无法实现短路规则
            内置版本的&& || 首先计算左边的表达式
    常规建议
  • 相关阅读:
    以用户需求为核心能玩出什么新花样?魅族 19 主理人计划构建理想机型
    NLP之TextLSTM(预测单词下一个字母)
    微信小程序将后端返回的图片文件流解析显示到页面
    SQL学习记录
    想要精通算法和SQL的成长之路 - 划分字母区间
    如何在用pip配置文件设置HTTP爬虫IP
    高斯金字塔的秘密(二,加速高斯,c#实现)
    Docker文档阅读笔记-How to Commit Changes to a Docker Image with Examples
    仿东郊到家小程序源码 同城按摩源码 家政小程序源码 美容理疗小程序源码+公众号H5+APP源码
    uniapp上echarts地图钻取
  • 原文地址:https://blog.csdn.net/2301_77164542/article/details/132852744