文章目录
0. 前言
构造函数、析构函数、拷贝构造、赋值重载、取地址重载-普通对象和const对象取地址。
像下面这两种就是取地址重载,一般我们使用默认的就可以了,除非你不想让别人找到你的地址这种情况就可以用了。
class Date
{
public :
Date* operator&()
{
return this ;
}
const Date* operator&() const
{
return this ;
}
private :
int _year ; // 年
int _month ; // 月
int _day ; // 日
};
谈到这里可能,部分友友不知到这段代码什么意思?
const Date* operator&() const
类的成员函数还有一个隐形的this指针,而后面const,就是修饰*this也就是this指向的内容。
//const Date* operator&(const Date* const this)
这只是方便理解,实践中在类内部不要这样写。
稍微转换一下,变成可读的代码就是这样了。
划到此处,我们谈谈本章对日期类的应用。
00. 链接
01. 日期类的实现–声明
这个标题内容,写的是日期的大概方向;感兴趣的友友们可以多写几个,例如:日期转换星期,或者写个菜单来感受一番小程序的乐趣。
写之前注意声明和定义分离,小丁现阶段用的是vs2019
声明–内联函数就直接放在声明里。
#pragma once
#include<assert.h>
#include<iostream>
using std::cout;
using std::endl;
using std::cin; //展开部分。
using std::ostream;
using std::istream;
//#include<iostream>
//using namespace std; 全部展开。
class Date
{
public:
// 获取某年某月的天数
int GetMonthDay(int year, int month)
{
static int days[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int day = days[month];
if ((month == 2) && ((year % 400 == 0) ||
(year % 4 == 0 && year % 100 != 0)))
{
day += 1;
}
return day;
}
//检查输入日期是否合理性。
bool CheckDate();
// 全缺省的构造函数
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
assert(!CheckDate());
}
// 拷贝构造函数
// 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) const;
// 日期-天数
Date operator-(int day) const;
// 日期-=天数
Date& operator-=(int day);
// 前置++
Date& operator++();
// 后置++
Date operator++(int);
// 后置--
Date operator--(int);
// 前置--
Date& operator--();
// >运算符重载
bool operator>(const Date& d) const;
// ==运算符重载
bool operator==(const Date& d) const;
// >=运算符重载
bool operator >= (const Date& d) const;
// <运算符重载
bool operator < (const Date& d) const;
// <=运算符重载
bool operator <= (const Date& d) const;
// !=运算符重载
bool operator != (const Date& d) const;
// 日期-日期 返回天数
int operator-(const Date& d) const;
//打印日期
void Print() const
{
cout << _year << '/' << _month << '/' << _day << endl;
}
//友元,可以让它访问私有成员变量。
//流插入和流提取没有直接打印或输入的日期,这需要我们来写一个运算符重载。
friend ostream& operator<<(ostream& out, const Date& d); //流插入
friend istream& operator>>(istream& in, Date& d); //流提取
private:
int _year;
int _month;
int _day;
};
inline ostream& operator<<(ostream& out, const Date& d)
{
out << d._year << '/' << d._month << '/' << d._day << endl;
return out;
}
inline istream& operator>>(istream& in, Date& d)
{
in >> d._year >> d._month >> d._day;
return in;
}
#include<iostream>
using std::cout;
using std::endl;
using std::cin; //展开部分。
using std::ostream;
using std::istream;
//#include<iostream>
//using namespace std; 全部展开。
顺便提一下,部分展开比全部展开更安全;只展开常使用的,这是一个较好的习惯。
友元,可以让它访问私有成员变量。
friend ostream& operator<<(ostream& out, const Date& d);
friend istream& operator>>(istream& in, Date& d);前面全局函数前面加个friend这个关键字,外面函数就可以访问私有成员变量了。
注意:友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。
这个时候,友友们就会像我直接放在类实现来实现流插入和流提取,确实可以。
istream& operator>>(istream& in,)
ostream& operator<<(ostream& out)
确实可以,可是只能 d1>>d2>>cin d1<<d2<<cout这样调用, 不仅别扭还可能误导人。
02. 日期类的实现–构造函数
构造函数分两种
// 1.无参构造函数
Date()
{}
// 2.带参构造函数
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
我们可以写个缺省函数来玩。
// 全缺省的构造函数
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
//检查日期是否合法。
assert(!CheckDate());
}
03. 日期类的实现–拷贝构造函数
拷贝构造函数就是构造函数的一个重载形式,只有一个参数类型;我们使用类类型的引用。
// 拷贝构造函数
// d2(d1)
Date::Date(const Date& d) //Date:: 就像一个指示牌,来在类里查找。
{
_year = d._year;
_month = d._month;
_day = d._day;
}
没什么可说的。
04. 日期类实现–赋值运算符重载
赋值运算符重载注意不要与拷贝构造函数弄混。
例子:
1.Date d1;
1.Date d2(d1);或者这样写Date d2=d1;
2.Date d1;
2.Date d2(2022, 7, 26);
2.d1=d2;
明显看出1.是拷贝构造函数,2.是赋值运算符重载。
// 赋值运算符重载
// d2 = d3 -> d2.operator=(&d2, d3)
Date& Date::operator=(const Date& d)
{
if (this != &d) //防止出现d1=d1,这种自己给自己的。
{
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this;
}
注意:引用的使用和范围。
05. 日期类实现–日期与天数的加减
// 日期+=天数
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 > 12) //十三月份就是,下一年的一月份。
{
++_year;
_month = 1;
}
}
return *this;
}
// 日期+天数
Date Date::operator+(int day) const
{
Date ret = *this;
ret += day;
return ret;
}
// 日期-天数
Date Date::operator-(int day) const
{
Date ret = *this;
ret -= day;
return ret;
}
// 日期-=天数
Date& Date::operator-=(int day)
{
if (day < 0)//防止传参传个负数。
{
return *this += -day;
}
_day -= day;
while (_day <= 0)
{
_day += GetMonthDay(_year, _month);
--_month;
if (_month == 0)
{
--_year;
_month = 12;
}
}
return *this;
}
-=或+=都需要返回值,我们使用引用;而且还可以实现-或+的时候复用一下。
// 前置++
Date& operator++();
// 后置++
Date operator++(int);
// 后置--
Date operator--(int);
// 前置--
Date& operator--();
明显看出前置与后置的区别是又没有int,int只是用来区分,想传参也可以传。
// 前置++
Date& Date::operator++()
{
*this += 1;
return *this;
}
// 后置++
Date Date::operator++(int)
{
Date ret = *this;
*this += 1;
return ret;
}
// 后置--
Date Date::operator--(int)
{
Date ret = *this;
*this -= 1;
return ret;
}
// 前置--
Date& Date::operator--()
{
*this -= 1;
return *this;
}
06. 日期类实现–运算符重载
// >运算符重载
bool Date::operator>(const Date& d) const
{
if ((_year > d._year) ||
(_year > d._year && _month > d._month) ||
(_year > d._year && _month > d._month && _day > d._day))
{
return true;
}
return false;
}
// ==运算符重载
bool Date::operator==(const Date& d) const
{
if (_year == d._year &&
_month == d._month &&
_day == d._day)
{
return true;
}
return false;
}
// >=运算符重载
bool Date::operator >= (const Date& d) const
{
return(*this == d) || (*this > d);
}
// <运算符重载
bool Date::operator < (const Date& d) const
{
return !(*this >= d);
}
// <=运算符重载
bool Date::operator <= (const Date& d) const
{
return !(*this > d);
}
// !=运算符重载
bool Date::operator != (const Date& d) const
{
return !(*this == d);
}
注意:复用。
06. 日期类实现–日期减日期并返回天数
// 日期-日期 返回天数。
int Date::operator-(const Date& d) const
{
//找最小和最大
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 flag * n;
}
注意:复用。
00// 展示:
最后还有一个判断函数参上:
//检查日期是否合理
bool Date::CheckDate()
{
if ((_month > 0 && _month <= 12) ||
(_day > 0 && _day <= GetMonthDay(_year, _month)))
{
return true;
}
return false;
}
测试用例自己随便写一些,我的测试用例测试后如图:
.
.
.
感觉有所收获的话,友友们给小丁一个赞👍。