• C++学习笔记-操作符重载


    操作符重载(operator overloading)是一种形式的C++多态,C++将操作符重载扩展到用户自定义的类型,如允许使用+将两个自定义的对象相加,编译器将根据操作数的数目和类型决定使用那种加法定义。

    要重载操作符,需使用操作符函数,格式如下:

    operator op (argument-list)

    op:要重载的操作符

    argument-list: 操作数

    操作符函数可以是类的成员函数,也可以是友元函数,如果是类成员函数,则第一个操作数是调用对象,它不在argument-list中。

    操作符重载范例,定义一个时间类Time,重载 + - *操作符。

    //Time.h

    #ifndef TIME_H_
    #define TIME_H_
    #include <iostream>
    class Time
    {
    public:
        Time(void);
        Time(int h,int m = 0);
        ~Time(void);
        void AddMin(int m);
        void AddHr(int h);
        void Reset(int h = 0, int m = 0);
        void Show()const;
        //重载 +操作符
        Time operator+ (const Time & t)const;
        Time operator- (const Time & t)const;
        // *
        Time operator* (double n) const;
        //友元函数
        friend Time operator* (double n, const Time & t);
        //重载<<操作符
        friend std::ostream & operator<< (std::ostream & os, const Time & t);
    
    private:
        int m_hours;
        int m_minutes;
    };
    #endif

    //具体实现 Time.cpp

     1 #include "Time.h"
     2 
     3 
     4 Time::Time(void)
     5     :m_hours(0)
     6     ,m_minutes(0)
     7 {
     8 }
     9 
    10 Time::Time(int h,int m)
    11     :m_hours(h)
    12     ,m_minutes(m)
    13 {
    14 }
    15 
    16 
    17 Time::~Time(void)
    18 {
    19 }
    20 
    21 void Time:: AddMin(int m)
    22 {
    23     m_minutes += m;
    24     m_hours += m_minutes / 60;
    25     m_minutes = m_minutes % 60;
    26 }
    27 void Time::AddHr(int h)
    28 {
    29     m_hours += h;
    30 }
    31 void Time::Reset(int h, int m)
    32 {
    33     m_hours = h;
    34     m_minutes = m;
    35 }
    36 void Time::Show()const
    37 {
    38     std::cout << m_hours << ":" << m_minutes;
    39 }
    40 Time Time::operator+ (const Time & t)const
    41 {
    42     Time sum;
    43     sum.m_minutes = m_minutes + t.m_minutes;
    44     sum.m_hours = m_hours + t.m_hours + sum.m_minutes / 60;
    45     sum.m_minutes = sum.m_minutes % 60;
    46     return sum;
    47 }
    48 Time Time::operator- (const Time & t)const
    49 {
    50     Time diff;
    51     int total1,total2;
    52     total1 = m_minutes + m_hours * 60;
    53     total2 = t.m_minutes + t.m_hours * 60;
    54     diff.m_hours = (total1 - total2) / 60;
    55     diff.m_minutes = (total1 - total2) % 60;
    56     return diff;
    57 }
    58 Time Time::operator* (double n) const
    59 {
    60     Time result;
    61     long total_minutes = m_hours * 60 * n + m_minutes * n;
    62     result.m_hours = total_minutes / 60;
    63     result.m_minutes = total_minutes % 60;
    64     return result;
    65 }
    66 
    67 Time operator* (double n, const Time & t)
    68 {
    69     Time result;
    70     long total_minutes = t.m_hours * 60 * n + t.m_minutes * n;
    71     result.m_hours = total_minutes / 60;
    72     result.m_minutes = total_minutes % 60;
    73     return result;
    74 }
    75 
    76 std::ostream & operator<< (std::ostream & os, const Time & t)
    77 {
    78     os << t.m_hours << ":" << t.m_minutes;
    79     return os;
    80 }
    View Code
    Time operator- (const Time & t)const;
    重载减法操作符后,可以很方便对Time对象进行减法运算
    Time start_time(10,40);
    Time end_time(11,50);

    Time diff_time = end_time - start_time;
    操作符函数为成员函数时,操作符左侧的对象是调用对象,右侧的为参数传递的对象,如上述减法操作实际上等同于:
    end_time.operator-(start_time);


    关于操作符重载:
    1、重载限制
    1)重载后的操作符必须至少有一个操作数是自定义类型,主要是防止用户为标准类型重载操作符。
    2)使用操作符不能违反操作符原来的句法规则。如 % 是二元操作符,需要两个操作数,不能将它重载成使用一个操作数。
    3)不能修改操作符的优先级
    4)不能定义新的操作符
    5)以下操作符不能重载:
    sizeof
    .
    .*        --成员指针操作符
    ::
    ?:         --条件运算符
    typeid       --一个RTTI操作符
    const_cast    --强制类型转换符
    dynamic_cast
    reinterpret_cast
    static_cast
    6)大部分操作符都可以通过成员函数或非成员函数进行重载,但下面的操作符只能通过成员函数重载:
    = 赋值操作符
    () 函数调用操作符
    [] 下标操作符
    -> 通过指针访问类成员的操作符

    2、通过友元函数重载
    对于很多操作符来说,可以选择使用成员函数或非成员函数来实现操作符重载。一般来说非成员函数应该是友元函数,这样才可能直接访问类的私有数据。
    如对于Time类的加法操作符:

    使用类成员函数重载
    Time operator+ (const Time & t)const;

    使用非成员函数重载:
    friend Time operator+ (const Time & t1, const Time & t2);

    对于成员函数版本,一个操作数通过this指针隐式传递,一个通过参数表
    友元版本,两个操作数都作为参数来传递
    这两种重载方式都能匹配 T1+T2
    但在重载操作符中,只能选择其中的一种格式,同时定义被视为二义性错误,导致编译错误。

    有些情况必须使用友元来重载
    在Time类中,*乘法操作符与其他两种重载的操作符不同,它使用了两种不同的类型,将一个Time值与一个double值结合在一起,这限制了该操作符的使用方式
    *使用成员函数重载如下:
    Time operator* (double n) const;
    意味着只能这样使用该操作符 A = B * 2.5 --> A = B.operator*(2.5) (注:左侧操作数应是调用对象)

    如果这样使用将导致编译错误 A = 2.5 * B (左侧操作数是调用对象,而2.5不是对象)

    这种情况可以用非成员函数来解决,由于要访问私有数据,故定义为友元函数:
    friend Time operator* (double n, const Time & t);

    此时,A = 2.5 * B --> A = operator*(2.5,B)
    对于非成员重载操作符函数,op左边的操作数对应第一个参数,op右边的操作数对应第二个参数。

    创建友元:
    a、友元函数的原型应放在类声明中,并加上friend关键字
    friend Time operator* (double n, const Time & t);
    operator*在类中声明,但不是类的成员函数,但与成员函数具有相同的访问权限

    b、在cpp文件中定义函数,由于不是成员函数,故不使用::限定符,也不要在定义中使用friend关键字

    总结:类的友元函数是非成员函数,其访问权限与类成员函数相同。

    3、常见的友元,重载<<操作符
    重载<<操作符,使之能与cout一起来输出对象的内容

    原型:
    friend std::ostream & operator<< (std::ostream & os, const Time & t);
    实现如下:
    std::ostream & operator<< (std::ostream & os, const Time & t)
    {
        os << t.m_hours << ":" << t.m_minutes;
        return os;
    }
    如此以来就可以直接输出Time对象
    Time t(10.50)
    cout << t;

    一般来说,要重载<<操作符来显示c_name对象,可使用友元函数,定义如下:
    ostream & operator<< (ostream & os, const & c_name obj)
    {
      os << ....; //输出对象内容
      return os;
    }
    之所以要返回ostream的引用,主要作用是可以拼接输出,如 cout << "Current Time:" << t << " ";


     



  • 相关阅读:
    如何下载无水印的抖音视频?
    @valid和自定义异常
    Centos7查看外网ip,yum安装的curl无法正常使用
    ElasticSearch安装
    Redis的主从架构+哨兵模式
    Redis的持久化方式
    Nacos 注册中心集群搭建
    kafka安装流程
    WinUI 3学习笔记(1)—— First Desktop App
    .NET 5学习笔记(12)——WinUI 3 Project Reunion 0.5
  • 原文地址:https://www.cnblogs.com/cmranger/p/4084254.html
Copyright © 2020-2023  润新知