• C++语法——详解运算符重载


    运算符重载是C++的一个重要特性。有了运算符重载,在代码编写时能更好的实现封装。

    目录

    一.运算符重载介绍

    二.运算符重载形式

    (一).参数

    (二).返回值

    (三).应用

    三.特殊的运算符重载

    (一).默认赋值运算符重载

    (二).自增运算符A++与++A

    (三).流提取>>与流插入<<

    四.不能进行重载的运算符


     

    一.运算符重载介绍

    运算符重载,就是让原本已经存在的运算符有了新的用法和意义。

    比如我们熟知的减号(-),原本是用来进行数字的相减处理。但经过运算符重载后,它可以用来进行其他类型的相减,像时间相减、日期相减、字符相减等等。只要是你能想到的,通过运算符重载基本都能够实现。

    对于C++而言,运算符重载一般是作为类的成员函数出现。因为当我们需要运算符重载时,往往是类中一种特殊的类型需要处理或者类本身需要处理。就像我们可能会把时间作为一个类,里面有小时、分钟、秒。如果让时间相减,那么减号的参数类型就变成了时间类。因此,重载最好作为类的成员函数出现,减少在我们调用运算符重载时发生冲突的可能。

    二.运算符重载形式

    [返回值] operator[运算符] (参数...) { ... };

    (一).参数

    第一点:

    这里我们必须注意的是,重载的参数个数必须与运算符原意的个数一致。比如+号的参数就是左加数和右加数两个。那么当我们重载加号时也要保证有左右两个加数作为参数。

    第二点:

    重载作为普通函数时:

    单目:右操作数是形参;双目:左边形参作为运算符左操作数,右边形参是右操作数。

    重载作为类的成员函数时:

    如果运算符参数只有一个,那么不需要写参数;如果运算符参数有两个,那么只需要写一个参数。

    因为类的成员函数默认有一个this指针。它会直接指向类本身。换句话说,当我们写出运算符重载时,有一个参数就已经被this指针包含了。

    单目运算符,this所指向运算符右参数,因为单目运算符的参数一般都在右边。

    双目运算符,this指向运算符左参数。

    以减号为例,两个时间类a和b相减时。如果是a - b,那么this指针指向a,反之则指向b。在声明函数时,我们只需要写右参数即可。a - b的话只需要写 int operator-(Time b);

    当然,单目运算符由于只有一个参数,且该参数被this所指向,那么我们无需声明任何参数即可。

    (二).返回值

    运算符的返回值类型取决于该重载函数的作用是什么。

    比如a + b的作用是得到一个加数,那么返回值就是a+b的值。a += b的作用是让a的值改变,既然是让参数a的值改变,那么就无需返回值。

    还有就是如果我们需要运算符支持多次操作那么也需要返回值。比如流插入运算符<<。我们可能需要多次进行插入,像cout << a << b << c;之类就需要返回流ostream本身以便于之后的流插入工作。

    (三).应用

    下面,我来为大家展示几种运算符重载方式:

    加号(双目):

    1. class Time
    2. {
    3. int _hour;
    4. int _min;
    5. int _sec;
    6. public:
    7. Time(int hour = 0, int min = 0, int sec = 0)
    8. {
    9. _hour = hour;
    10. _min = min;
    11. _sec = sec;
    12. }
    13. void Print()
    14. {
    15. cout << _hour << ":" << _min << ":" << _sec << endl;
    16. }
    17. Time operator+(int min)//加分钟
    18. {
    19. Time t(*this);//因为是+号,规定不能改变左右参数的值,所以使用t来取和用以返回。
    20. t._min += min;
    21. if (t._min > 59)//检查时间正确性
    22. {
    23. t._hour += (t._min / 60);
    24. if (t._hour > 23)
    25. t._hour /= 24;
    26. t._min %= 60;
    27. }
    28. return t;
    29. }
    30. };
    31. int main()
    32. {
    33. Time a(10, 30, 30);
    34. (a + 140).Print();
    35. return 0;
    36. }

    88d69da49812462ab1fbcd915494b641.png

     自增(单目):

    1. class Time
    2. {
    3. int _hour;
    4. int _min;
    5. int _sec;
    6. public:
    7. Time(int hour = 0, int min = 0, int sec = 0)
    8. {
    9. _hour = hour;
    10. _min = min;
    11. _sec = sec;
    12. }
    13. void Print()
    14. {
    15. cout << _hour << ":" << _min << ":" << _sec << endl;
    16. }
    17. int& operator++()// ++a和a++分别如何我们之后会讲到,这里使用++a
    18. {
    19. return _hour += 1;//为方便演示,让小时+1,但不再判断时间正确性
    20. }
    21. };
    22. int main()
    23. {
    24. Time a(10, 30, 30);
    25. ++a;
    26. a.Print();
    27. return 0;
    28. }

    fa0b3d8851014319b49d074c608d1e11.png

    三.特殊的运算符重载

    (一).默认赋值运算符重载

    即便我们没有手动定义赋值运算符重载,C++也为我们提供了默认函数。

    在默认赋值重载中,内置类型按字节拷贝,自定义类型会去调自己的默认赋值重载。这点与默认拷贝构造极为相似,不懂的可以看看这篇文章:详解析构函数、拷贝构造函数

    因此,当我们的类中只有int、char、double之类内置类型时,无需再写赋值重载。

    但是,如果有指针、malloc、new之类指向地址、手动开辟空间的,一般情况下还是需要手写重载的。

    总而言之,默认赋值重载只能进行浅拷贝,是否需要手动去写要根据类的成员类型判断。

    1. class Time
    2. {
    3. int _hour;
    4. int _min;
    5. int _sec;
    6. public:
    7. Time(int hour = 0, int min = 0, int sec = 0)
    8. {
    9. _hour = hour;
    10. _min = min;
    11. _sec = sec;
    12. }
    13. void Print()
    14. {
    15. cout << _hour << ":" << _min << ":" << _sec << endl;
    16. }
    17. };
    18. int main()
    19. {
    20. Time a;
    21. Time b(20, 10, 50);
    22. a.Print();
    23. a = b;//调用默认赋值重载
    24. a.Print();
    25. return 0;
    26. }

    a9dbcc016b0a495eae7479fab38619df.png 值得注意的一点是:

    我们需要分清楚赋值重载与拷贝构造的区别。

    拷贝构造只能发生在对象被定义时,而赋值则是在对象已经被定义完毕后。

    1. void main()
    2. {
    3. Time A;
    4. Time T = A;//拷贝构造
    5. Time B;
    6. B = A;//赋值重载
    7. }

    (二).自增运算符A++与++A

    因为单目运算符重载的this指针指向右边,所以按正常写法我们写出来的是++A。

    C++规定,A++的写法是在正常++运算重载基础上,在参数上写一个int类型的参数。

    方式如下:

    1. class Time
    2. {
    3. int _hour;
    4. int _min;
    5. int _sec;
    6. public:
    7. Time(int hour = 0, int min = 0, int sec = 0)
    8. {
    9. _hour = hour;
    10. _min = min;
    11. _sec = sec;
    12. }
    13. void Print()
    14. {
    15. cout << _hour << ":" << _min << ":" << _sec << endl;
    16. }
    17. //为方便演示,让小时+1,但不再判断时间正确性
    18. Time& operator++()// ++A
    19. {
    20. _hour += 1;
    21. return (*this);//因为自增直接返回this用引用接收
    22. }
    23. Time operator++(int)//A++,参数写int或int i都可以
    24. {
    25. Time ret(*this);
    26. _hour += 1;
    27. return ret;//需要返回this自增之前的结果,所以用临时变量返回
    28. }
    29. };
    30. int main()
    31. {
    32. Time a(10, 30, 30);
    33. //(++a).Print();
    34. //a.Print();
    35. (a++).Print();
    36. a.Print();
    37. return 0;
    38. }

     905f9e3008ba4192a82de5e0f8d008bb.png

    aa1bf46c8b5441b0a4b09d0076e93cb5.png 

    (三).流提取>>与流插入<<

    对于流而言,因为是双目运算符,this指针本应该指向左边的类,但左操作数是一个流,又与this的类型冲突。那么就会出现很奇怪的现象:

    b2f005e4e1e241fcbf75a25bfe645af0.png

    因为this指针会默认指向类,而我们需要让左参数指向流,右参数指向类。所以重载就不能作为类的成员函数出现了。

    这时,就需要用到友元函数friend。友元函数本身是一个普通函数,但是作为类的友元,能够调用类内的成员,包括private。而且参数不用被类限制为第一个必须是this所指的对象本身。

    使用时,我们只需要在类内声明有个友元函数即可。

    1. #include"head.h"
    2. class Time
    3. {
    4. friend ostream& operator<<(ostream& out, Time& t);//友元函数,声明
    5. friend istream& operator>>(istream& in, Time& t);
    6. int _hour;
    7. int _min;
    8. int _sec;
    9. public:
    10. Time(int hour = 0, int min = 0, int sec = 0)
    11. {
    12. _hour = hour;
    13. _min = min;
    14. _sec = sec;
    15. }
    16. };
    17. ostream& operator<<(ostream& out, Time& t)//流插入
    18. {
    19. out << t._hour << ":" << t._min << ":" << t._sec << endl;
    20. return out;
    21. }
    22. istream& operator>>(istream& in, Time& t)//流提取
    23. {
    24. in >> t._hour >> t._min >> t._sec;
    25. return in;
    26. }
    27. int main()
    28. {
    29. Time a;
    30. cin >> a;
    31. cout << a;
    32. return 0;
    33. }

    52c7ddf3962840d0bbbcca357c3d05e0.png 

    四.不能进行重载的运算符

    在C++中有几种运算符不能进行重载

    .*任意字符出现零次或多次
    ::域作用符
    sizeof大小
    ? :三目运算符
    .点运算符

     

     

    • “优良设计创造价值的速度,快于其增加成本的速度。”——托马斯·C.盖勒(Thomas C.Gale)

     如有错误,敬请斧正

     

     

  • 相关阅读:
    TCP补充
    Git入门(建议收藏)
    Win:将一般用户添加到 Local Admins 组中
    AMRT3D数字孪生引擎详解
    关于QUERY_ALL_PACKAGES权限导致Google下架apk
    read 方法为什么返回 int 类型
    Python自动操作 GUI 神器——PyAutoGUI
    1021 Deepest Root
    Spring高手之路10——解锁Spring组件扫描的新视角
    质量、重力和重量
  • 原文地址:https://blog.csdn.net/weixin_61857742/article/details/126010673