C++ 运算符重载(日期类)

运算符重载


为什么要有运算符重载
  • 我们首先定义一个日期类:
class Date
{
public:
    Date(int year=2018,int month=4,int day=25)
        :_year(year)
        ,_month(month)
        ,_day(day)
    {}
private:
    int _year;
    int _month;
    int _day;
}
  • 我们都知道,对于内置类型,我们可以使用”+、-、*、/、++、–、……”等运算符,内置类型天然支持这些运算符
  • 但是对于类似于上面我们定义的日期类等自定义类型,这些默认的操作符将不再适用;比如说我们想比较两个日期是否相等,当然我们可以使用一个函数IsEqual(const Date& d1,const Date& d2)来实现这个功能,每次需要比大小的时候就可以调用这个函数,但是使用的前提是你得认识这个单词或者这个函数前面有注释
  • C++中支持这样一种机制——运算符重载,我们可以自定义运算符,然后可以同内置类型一样使用这些操作符,比如说我们比较两个日期是否相等,我们可以直接这样操作 int a=d1==d2;这样我们通过返回值就可以判断是否相等,显然大家都认识==这个操作符是用来比较是否相等的
  • 所以,运算符重载要比函数调用来的方便直观的多,在C++中对于这种自定义类型得运算,我们通常都是通过运算符重载来完成的
运算符重载特征
  • operator合法的运算符——构成函数名(operator+:重载+运算符)
  • 重载运算符以后,不能改变运算符的优先级/结合性/操作数个数
  • 五个不能重载的运算符(以、分隔):.*::sizeof?:.

基于日期类实现运算符重载


一个基本的日期类
  • 包括成员变量,有必要自己实现的默认成员函数
class Date
{
public:
    //构造早一个日期对象并对其赋初值,不能有非法值(考虑闰年,2月,负值,大小月等因素)
    Date(int year=2018,int month=4,int day=25)
        :_year(year)
        ,_month(month)
        ,_day(day)
    {
        if(!IsLegal())
        {
            assert(false);
        }
    }

    bool IsLegal()
    {
        return _year > 0
            && _month > 0 && _month <= 12
            && _day > 0 && _day <= GetMonthDay(_year, _month);
    }

    //获得当前月的天数
    int GetMonthDay(int year, int month)
    {
        int days[] = { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
        int monthday = days[month];
        if (month == 2 && IsLeapYear(year))
        {
            monthday = 29;
        }
        return monthday;
    }

    //判断当前年是否是闰年
    bool IsLeapYear(int year)
    {
        return year % 4 == 0 && year % 100 != 0
            || year % 400 == 0;
    }

    //赋值运算符重载,d1=d2(返回值为d1,左值,即隐含的this指针)
    //因为隐含this形参作用域为整个类域,所以返回值为引用(避免拷贝构造带来的开销)
    Date& operator=(const Date& d)
    {
        _year = d._year;
        _month = d._month;
        _day = d._day;
        return *this;
    }

    //Date(const Date& d)
    //{
    //  _year=d._year;
    //  _month=d._month;
    //  _day=d._day;
    //}
    //因为我们的日期类的成员变量都是内置类型,所以系统定义的拷贝构造函数够我们使用,所以可以不定义

    ~Date()
    {}
private:
    int _year;
    int _month;
    int _day;
}
日期类相关运算的运算符重载
    bool operator==(const Date& d)
    {
        return _year == d._year
            &&_month == d._month
            &&_day == d._day;
    }

    bool operator!=(const Date& d)
    {
        return !(*this == d);
    }

    bool operator>(const Date& d)
    {
        return _year > d._year
            || _year == d._year&&_month > d._month
            || _year == d._year&&_month == d._month&&_day > d._day;
    }

    bool operator<(const Date& d)
    {
        return !(*this>d && *this == d);

    bool operator>=(const Date& d)
    {
        return (*this > d)||(*this==d);
    }

    bool operator<=(const Date& d)
    {
        return !(*this > d);
    }
  • 在上面的实现中,我们并没有给每一个函数按照它的逻辑一步步的定义,更多的是复用已写的代码
  • 注意:不要嵌套调用。大家可以看到我写了一个>,复用了>和==实现了<;<=我是用>实现的,但是>=我并没有用<实现,因为<又会去调用>和==,这样的实现时容易出错的,所以大家在复用的时候应该注意这些问题
    Date operator+(int day)
    {
        if (day<0)
        {
            return (*this) - (-day);
        }

        Date& ret(*this);
        ret._day += day;
        while (ret._day > GetMonthDay(ret._year, ret._month))
        {
            int monthday = GetMonthDay(ret._year,ret._month);
            ret._day -= monthday;
            ret._month++;
            if (ret._month == 13)
            {
                ret._year++;
                ret._month = 1;
            }
        }
        return ret;
    }
    Date operator-(int day)
    {
        if (day < 0)
        {
            return (*this) + (-day);
        }

        Date& ret(*this);
        ret._day -= day;
        while (ret._day <= 0)
        {
            if (ret._month == 1)
            {
                ret.GetMonthDay = 12;
                --ret._year;
            }
            else
            {
                --ret._month;
            }
            int monthday = GetMonthDay(ret._year, ret._month);
            ret._day += monthday;
        }
        return ret;
    }

    Date& operator+=(int day)
    {
        *this = *this + day;
        return *this;

    Date& operator-=(int day)
    {
        *this = *this - day;
        return *this;
    }
  • +运算符的重载思想是:若加的天数>0,并且相加后天数超过当月天数,则我们需要向月进位,同时减掉当月天数;如果进位后月份为13了,则向年进位同时置月份为1
  • -运算符的重载思想是:若减的天数>0,并且相减的天数小于0,则我们需要向月借位,如果月份减到1了,则需要向年借位,同时置月份为12,年份减1
    int operator-(const Date& d)
    {
        Date& max(*this);
        Date min(d);
        int flag = 1;
        if (*this < d)
        {
            min = *this;
            max = d;
            flag = -1;
        }
        int days = 0;
        while (min < max)
        {
            min++;
            days++;
        }
        return days*flag;
    }
  • 日期-日期:我们需要考虑的是哪个操作数大,让小的日期往大的日期那边加,这样加的天数就是两个日期之间差的天数。如果我们不比较大小的画,那么减出来的结果可能为正可能为负
    //前置,返回值为加后的值
    Date& operator++()
    {
        *this += 1;
        return *this;
    }

    Date& operator--()
    {
        *this -= 1;
        return *this;
    }

    //后置++,返回值为加前的值
    Date operator++(int)
    {
        Date ret(*this);
        *this += 1;
        return ret;
    }

    Date operator--(int)
    {
        Date ret(*this);
        *this -= 1;
        return ret;
    }
  • 前置++和后置++函数名相同,用参数来进行区分,带参的为后置++,这两个运算符构成重载

猜你喜欢

转载自blog.csdn.net/aurora_pole/article/details/80028366
今日推荐