赋值运算符重载(补充)
- “ .* ”、 “ :: ”、“ sizeof ”、“ ?: ”、“ . ”这五个运算符不能重载,考试的时候爱考需要记一下。
- 重载操作符至少有一个类类型的参数,不能通过运算符重载改变内置类型对象的含义,如下代码所示:
- 一个类需要重载哪些运算符,要看那些运算符重载后有意义,例如在Date类重载“ * ”没有意义,因为两个日期相乘没意义,而“ - ”有意义,因为可以计算两个日期中间相距多少天。
- 重载++运算符时,前置++和后置++的运算符重载函数名都是operator++,但为了区分前置和后置,C++规定后置++重载的时候增加一个int形参(),如代码所示:
- 重载<<和>>时需要为全局函数,因为重载作为成员函数时this指针默认抢了第一个形参位置,第一个形参位置则是左侧运算对象,所以调用时就变成了对象<<cout,不符合我们日常的使用习惯,所以我们重载在全局函数,把ostream/istream(cout/cin的类型)放在第一个形参位置上就可以了,第二个则是类类型。如下代码所示:
#pragma once #include<iostream> #include<assert.h> using namespace std; class Date { friend ostream& operator<<(ostream& out, const Date& d); friend istream& operator>>(istream& in, Date& d); } //重载<< ostream& operator<<(ostream& out, const Date& d) { out << d._year << "年" << d._month << "⽉" << d._day << "⽇" << endl; return out; } //重载>> istream& operator>>(istream& in, Date& d) { cout << "请依次输⼊年⽉⽇:>"; in >> d._year >> d._month >> d._day; if (!d.CheckDate()) { cout << "⽇期⾮法" << endl; } return in; }
对于上面代码的解释:在类里面对重载加了friend(友元)这使重载在全局区也可以使用类里面的私有成员变量,为了方便这里直接使用后面再补充这个内容;而重载函数的返回值是ostream&的原因是:当我们想打印多个变量a b c时我们直接cout<<a<<b<<c;但如果说我们的返回值是void的话就不能实现多个变量一起打印,由下面图:由这个图说明当打印完了a后需要返回cout才可以接着打印b,上面就是为了实现这个操作 函数的返回值才是ostream&,cin的也同理。
Date日期类的实现
- 首先我们要实现两个日期的比较大小,如果说我们一个一个实现那将要实现大于、小于、等于、大于且等于、小于且等于,太麻烦了,所以我们可以尝试先实现一个小于和等于,再通过赋用;举个例子,当我们实现了小于和等于,那么当我们要实现大于等于的时候就直接赋用小于然后取反,得到的就是大于或等于,其他也一样实现。如下代码:
Date.h:
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
class Date
{
public:
// >运算符重载
bool operator>(const Date& d);
// ==运算符重载
bool operator==(const Date& d);
// >=运算符重载
bool operator >= (const Date& d);
// <运算符重载
bool operator < (const Date& d);
// <=运算符重载
bool operator <= (const Date& d);
// !=运算符重载
bool operator != (const Date& d);
private:
int _year;
int _month;
int _day;
};
Date.cpp:
#include"Date.h"
// >运算符重载
bool Date::operator>(const Date& d)
{
if (_year > d._year)
{
return true;
}
else if (_year == d._year && _month > d._month)
{
return true;
}
else if (_year == d._year && _month == d._month && _day > d._day)
{
return true;
}
return false;
}
// ==运算符重载
bool Date::operator==(const Date& d)
{
return _year == d._year && _month == d._month && _day == d._day;
}
// >=运算符重载
bool Date::operator >= (const Date& d)
{
return *this > d || *this == d;
}
// <运算符重载
bool Date::operator < (const Date& d)
{
return !(*this >= d);
}
// <=运算符重载
bool Date::operator <= (const Date& d)
{
return !(*this > d);
}
// !=运算符重载
bool Date::operator != (const Date& d)
{
return !(*this == d);
}
-
实现Date前准备工作
- 我们要创建一个构造函数进行初始化也就是接收用户输入的年月日,再实现一个获取传入月份的天数,然后再实现一个检查日期是否合法的函数,因为要保证用户输入的日期是合法的,实现思路:用bool类型创建一个CheckDate(),在函数里面判断月份小于0或大于12,然后还有天数小于1或天数大于该月的天数代码如下:
#pragma once
#include<iostream>
using namespace std;
#include<assert.h>
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1);
//获取传入月份的天数
int GetMonthDay(int year, int month)
{
assert(month > 0 && month < 13);
static int monthDayArray[13] = { -1, 31, 28, 31, 30, 31, 30,31, 31, 30, 31, 30, 31 };
//判断是否为闰年,闰年2月29天
if (month == 2 && (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
{
return 29;
}
else
{
return monthDayArray[month];
}
}
bool CheckDate();
//打印函数
void Print();
// 拷贝构造函数
// d2(d1)
Date(const Date& d);
private:
int _year;
int _month;
int _day;
};
//类外实现
#include"Date.h"
//检查日期是否合法
bool Date::CheckDate()
{
if (_month > 12 || _month < 1 || _day<1 || _day>GetMonthDay(_year, _month))
{
return false;
}
else
return true;
}
//构造函数进行初始化
Date::Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
if (!CheckDate())
{
cout << "非法日期->" << *this;;
}
}
//拷贝构造函数
Date::Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
//打印函数
void Date::Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
- 我们就要实现日期的赋值、加减,一个日期赋值给另一个日期,一个日期+天数或者减日期-天数得到另一个日期,还有日期+=天数和日期-=天数;首先我们来说说赋值,赋值重载需要和拷贝构造分开,拷贝构造是实例化对象时拷贝一个对象的数据给那个被实例化的对象中去,而赋值重载实现的是两个被实例化好的对象d1 和d2, 把d1的数据传给d2,我们需要分清这两个;代码如下:
Date& Date::operator=(const Date& d) { _year = d._year; _month = d._month; _day = d._day; return *this; }
实现+=的重载
-
首先我们举个例子,a+=1简化后是a = a+1,a的值发生了变化所以我们需要直接对该对象进行处理,那么就需要返回*this(this指针指向调用该函数的对象)所以返回类型是Date&,然后实现该函数时需要注意当用户传来的值是负数时,此时+=就变成了-=,还要判断改变后的天数是否符合该月的天数,例如8月有31天、9月30天,如果说超过该月的天数则月份+1 ,天数-该月的天数,还要判断月份是否为13,如果月份为13则令month = 1,year++;代码如下:
Date& Date::operator+=(int day) { if (day < 0) { return *this -= day; } _day += day; while (_day > GetMonthDay(_year, _month)) { _day -= GetMonthDay(_year, _month); ++_month; if (_month == 13) { ++_year; _month = 1; } } return *this; }
实现+的重载
- +的重载与+=不同的是值本身不会发生变化,举个例子b = a+1,a不会发生变化;实现时我们可以创建一个临时变量,然后赋用+= 再返回临时变量,代码如下:
//这个与上面的实现不同,这个原对象不变 Date Date::operator+(int day) { Date temp(*this); temp += day; return temp; }
实现-=和-的重载
- 和上面一样,就不过多介绍,直接上代码:
//需要改变原对象 Date& Date::operator-=(int day) { if (day < 0) { return *this += day; } _day -= day; while (_day < 0) { _month--; if (_month == 0) { _month = 12; _year--; } _day += GetMonthDay(_year, _month); } return *this; } Date Date::operator-(int day) { Date temp = (*this); temp -= day; return temp; }
实现前置++
- 前置++是先++再返回值;代码如下:
Date& Date::operator++() { *this += 1; return *this; }
实现后置++
- 后置++与前置++不同的是,后置++是先返回值再++,那么我们就需要创建一个临时对象来保存++前的值然后返回++前的值,且为了分辨后置++的重载和前置++的重载,我们实现后置++时需要加上一个形参int,代码如下:
Date Date::operator++(int) { Date temp = *this; *this += 1; return temp; }
补充说明:当返回temp的时候我们的返回值是Date不是Date&,因为该函数结束后函数栈帧销毁,此时如果返回的是Date&则会出现野引用,因为temp被销毁了。
实现前置--
- 思路同上不过多介绍,直接上代码:
// 前置-- Date& Date:: operator--() { *this -= 1; return *this; }
实现后置--
-
// 后置-- Date Date::operator--(int) { Date temp = *this; *this -= 1; return temp; }
实现日期减日期
- 日期减日期得到的是两个日期之间相差的天数,这个对于日期计算来说是非常有必要实现的,实现思路是:首先我们需要找到一个大日期和小日期,Date实例化一个对象max保存*this,再实例化min保存d(因为我们不知道是*this的日期大还是d的日期大,就先创建然后再进行比较如果说*this的日期小于d的日期,则令max = d,min = *this);然后我们先思考两个日期如何相减,两个日期相减得到的还是一个日期,再把日期化为天数太麻烦了,所以我们可以尝试一个新思路:让小的日期++然后创建一个变量n=0,让小日期一直++且n也跟着++(n用来记录小日期++到大日期的次数),直到小的日期等于大的日期时停下,再返回n;代码如下:
// 日期-日期 返回天数 int Date:: operator-(const Date& d) { Date max = *this; Date min = d; int flag = 1; if (*this < d) { max = d; min = *this; flag = -1; } int n = 0; while (min != max) { ++min; ++n; } return n * flag; }
补充说明:举个例子说明flag的作用,假设输入的两个日期:2005.7.3到2004.1.10 那flag就等于1,得到的n是191天*flag(1) = 191,如果输入的两个日期是:2004.1.10到2005.7.3日(反过来了)则flag =-1,返回的值则是191*(-1) = -191;
整个Date日期类的代码
Date.h
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
class Date
{
public:
//检查月日是否非法
bool CheckDate();
// 获取某年某月的天数
int GetMonthDay(int year, int month)
{
assert(month > 0 && month < 13);
static int monthDayArray[13] = { -1, 31, 28, 31, 30, 31, 30,31, 31, 30, 31, 30, 31 };
//判断是否为闰年,闰年2月29天
if (month == 2 && (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
{
return 29;
}
else
{
return monthDayArray[month];
}
}
friend ostream& operator<<(ostream& out, const Date& d);
friend istream& operator>>(istream& in, Date& d);
void Print();
// 全缺省的构造函数
Date(int year = 1900, int month = 1, int day = 1);
// 拷贝构造函数
// d2(d1)
Date(const Date& d);
// 赋值运算符重载
// d2 = d3 -> d2.operator=(&d2, d3)
Date& operator=(const Date& d);
析构函数
//~Date();
// 日期+=天数
Date& operator+=(int day);
// 日期+天数
Date operator+(int day);
// 日期-=天数
Date& operator-=(int day);
// 日期-天数
Date operator-(int day);
// 前置++
Date& operator++();
// 后置++
Date operator++(int);
// 后置--
Date operator--(int);
// 前置--
Date& operator--();
// >运算符重载
bool operator>(const Date& d);
// ==运算符重载
bool operator==(const Date& d);
// >=运算符重载
bool operator >= (const Date& d);
// <运算符重载
bool operator < (const Date& d);
// <=运算符重载
bool operator <= (const Date& d);
// !=运算符重载
bool operator != (const Date& d);
// 日期-日期 返回天数
int operator-(const Date& d);
private:
int _year;
int _month;
int _day;
};
date.cpp
#include"Date.h"
bool Date::CheckDate()
{
if (_month > 12 || _month < 1 || _day<1 || _day>GetMonthDay(_year, _month))
{
return false;
}
else
return true;
}
Date::Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
if (!CheckDate())
{
cout << "非法日期->" << *this;;
}
}
Date::Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
void Date::Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
Date& Date::operator=(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
return *this;
}
Date& Date::operator+=(int day)
{
if (day < 0)
{
return *this -= day;
}
_day += day;
while (_day > GetMonthDay(_year, _month))
{
_day -= GetMonthDay(_year, _month);
++_month;
if (_month == 13)
{
++_year;
_month = 1;
}
}
return *this;
}
//这个与上面的实现不同,这个原对象不变
Date Date::operator+(int day)
{
Date temp(*this);
temp += day;
return temp;
}
//需要改变原对象
Date& Date::operator-=(int day)
{
if (day < 0)
{
return *this += day;
}
_day -= day;
while (_day < 0)
{
_month--;
if (_month == 0)
{
_month = 12;
_year--;
}
_day += GetMonthDay(_year, _month);
}
return *this;
}
Date Date::operator-(int day)
{
Date temp = (*this);
temp -= day;
return temp;
}
Date& Date::operator++()
{
*this += 1;
return *this;
}
Date Date::operator++(int)
{
Date temp = *this;
*this += 1;
return temp;
}
// 后置--
Date Date::operator--(int)
{
Date temp = *this;
*this -= 1;
return temp;
}
// 前置--
Date& Date:: operator--()
{
*this -= 1;
return *this;
}
// >运算符重载
bool Date::operator>(const Date& d)
{
if (_year > d._year)
{
return true;
}
else if (_year == d._year && _month > d._month)
{
return true;
}
else if (_year == d._year && _month == d._month && _day > d._day)
{
return true;
}
return false;
}
// ==运算符重载
bool Date::operator==(const Date& d)
{
return _year == d._year && _month == d._month && _day == d._day;
}
// >=运算符重载
bool Date::operator >= (const Date& d)
{
return *this > d || *this == d;
}
// <运算符重载
bool Date::operator < (const Date& d)
{
return !(*this >= d);
}
// <=运算符重载
bool Date::operator <= (const Date& d)
{
return !(*this > d);
}
// !=运算符重载
bool Date::operator != (const Date& d)
{
return !(*this == d);
}
// 日期-日期 返回天数
int Date:: operator-(const Date& d)
{
Date max = *this;
Date min = d;
int flag = 1;
if (*this < d)
{
max = d;
min = *this;
flag = -1;
}
int n = 0;
while (min != max)
{
++min;
++n;
}
return n * flag;
}
//重载<<
ostream& operator<<(ostream& out, const Date& d)
{
out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
return out;
}
//重载>>
istream& operator>>(istream& in, Date& d)
{
cout << "请依次输入年月日:>";
in >> d._year >> d._month >> d._day;
if (!d.CheckDate())
{
cout << "日起非法" << endl;
}
return in;
}
END!