1.Date中的构造函数
构造函数的作用可以说是对类变量的初始化(Init)如果我们不写构造函数,系统会生成默认的构造函数,但是对于date类来说,这里的默认构造函数什么都不做,如果你创建了一个 Date d1,系统调用了默认构造函数,你会发现这里的年月日都是随机值,我们为了让d1在初始化的时候就有一个确认的日期,所以得自己动手写一个全缺省的构造函数
我们在函数声明中给一个确定的值,让每个创建出来的日期类变量都有一个默认的初始值 1900,1,1
2.Date中的析构函数
析构函数的作用同构造函数是对应的,这里是销毁某些特定的成员变量,如我们用malloc申请出来的内存,如果不在析构函数中做特定的操作,就很可能导致内存泄漏,不过在Date中的成员并不需要特殊的去释放他,他们生长在栈上,会随函数栈桢的结束自动释放掉,所以这里就可以使用默认的析构函数,我们可以不用书写
3.Date中的拷贝构造函数
创建对象的时候使用同类对象初始化,拷贝构造函数其实是一个构造函数的重载,如果我们没有实现拷贝构造函数,系统也会自动生成拷贝构造函数,来依次拷贝类成员进行初始化
需要注意:拷贝构造函数必须使用传引用的方式返回,否则会造成无穷递归
4.Date中的运算符重载
这里我实现了如下几个运算符的重载
需要注意的是
1.当返回一个Date类的变量时,我们使用传值返回( 例如 + )还是传引用返回(例如 +=)?
可以这么说,所有需要返回一个Date类的函数都可以使用传值返回,可是传值返回在返回的过程中会生成一个临时变量,并且会调用一次构造函数,开销比较大,所以在可以使用传引用返回的情况下,我们最好有限考虑传引用返回。
传引用返回的条件是,你要返回的Date变量在出了当前函数作用域还存在(例如 静态变量static,或者是传值传进来的变量),只要生命周期大于这个函数的周期,就可以返回引用。当然还需要考虑这个变量应不应该被改变,例如使用 d1 + 1 的时候,d1是不需要被改变的,所以返回的值只可以是在类里面创建的变量。使用 d1 += 1的时候,d1的值会被改变掉,所以就可以直接返回改变以后的d1
2.为了提高我们写代码的效率,我们可以复用自己写过的运算符
例如,我们已经写好了一个 ' < '的运算符,当我们需要些 ‘ >= ’的时候就可以直接使用 ‘ !< ’,这样写不仅仅可以提高我们写代码的效率,还可以提高我们修改代码的效率,如果你有100函数都是用的相同逻辑,调用的是一个基础的函数,如果这个逻辑出错,修改的时候就只需要该基础函数的逻辑
3.区分前置++(--)和后置++(--)
相同点:两者的运算符都是 ++,所以易于混淆
不同点:因为本身难以区分,所以编译器帮了我们很大的忙,在调用++(--)运算符时,编译器当然可以辨别程序员输入的是前置还是后置,如果是后置,编译器在传参的时候就会传一个 int 类型的变量,在调用的时候如果发现什么参数都没有,那就默认是前置++(--),如果发现参数中有一个 int 类型的形参,那么就会处理成后置的++(--),但是这里的 int形参什么事情都不做,只是为了区分前置和后置
下面我们看一下完整代码:
//Date.h
#pragma once
class Date
{
public:
Date(int year = 1900,int month = 1,int day = 1);
~Date(){}
bool IsValid();
int GetMonthDay(int year,int month);
bool IsLeapYear(int year);
void Show();
Date& 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);
bool operator<(const Date& d);
Date operator+(int day);
Date& operator+=(int day);
Date operator-(int day);
Date& operator-=(int day);
int operator-(const Date& d);//日期-日期 返回天数
Date& operator++();//默认前置
Date operator++(int);//用参数标志后置++
Date& operator--();
Date operator--(int);
private:
int _year;
int _month;
int _day;
};
//date.cpp
#include "date.h"
#include <iostream>
#include <assert.h>
using namespace std;
Date::Date(int year,int month,int day):_year(year),_month(month),_day(day)
{
if(!IsValid()) // -> this.IsValid()
{
assert(false);
}
}
bool Date::IsValid()
{
return (_year > 0
&& _month > 0 && _month <= 12
&&_day > 0 && _day <= GetMonthDay(_year,_month));
}
int Date::GetMonthDay(int year,int month)
{
int arr[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
if(month == 2 && IsLeapYear(year))
{
++arr[2];
}
return arr[month];
}
bool Date::IsLeapYear(int year)
{
return ((year % 4 == 0 && year % 100 != 0)
|| year % 400 == 0);
}
void Date::Show()
{
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
// 运算符重载经历以下几个步骤
// (d1==d2)
// d1.operator==(d2)
// d1.operator==(&d1,d2)
// bool Date::operator==(Date* this,const Date& d)
bool Date::operator==(const Date& d)
{
if(_year == d._year && _month == d._month && _day == d._day)
return true;
return false;
}
//传值返回:会多调用一次拷贝构造函数
//传引用返回:直接返回,不需要调用拷贝构造
// 出了作用于变量还在,尽量使用传引用返回
Date& Date::operator=(const Date& d)
{
if(this != &d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this;
}
bool Date::operator>=(const Date& d)
{
return !(*this < d);
}
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)
{
if((_year < d._year) ||
(_year == d._year && _month < d._month) ||
(_year == d._year && _month == d._month && _day < d._day))
return true;
return false;
}
Date Date::operator+(int day)
{
if(day < 0)
{
return (*this) - (-day);
}
Date d(*this);
d._day += day;
while(d.IsValid() == false)
{
int month_day = GetMonthDay(d._year,d._month);
d._day -= month_day;
++d._month;
if(d._month > 12)
{
d._month = 1;
++d._year;
}
}
return d;
}
Date& Date::operator+=(int day)
{
*this = (*this + day);
return *this;
}
Date Date::operator-(int day)
{
if(day < 0)
{
return (*this) + (-day);
}
Date d(*this);
d._day -= day;
while(d.IsValid() == false)
{
--d._month;
if(d._month == 0)
{
--d._year;
d._month = 12;
}
int pre_month_day = GetMonthDay(d._year,d._month);
d._day += pre_month_day;
}
return d;
}
Date& Date::operator-=(int day)
{
*this = (*this - day);
return *this;
}
int Date::operator-(const Date& d)//日期-日期 返回天数
{
int flag = 1;
Date max = (*this);
Date min = d;
if((*this) < d)
{
max = d;
min = (*this);
flag = -1;
}
int count = 0;
while(max != min)
{
++min;
++count;
}
return flag*count;
}
// ++d1 -> d1.operator++(&d1);
Date& Date::operator++()//默认前置
{
*this += 1; // 只调用一个函数
//*this = *this + 1; //调用两个函数,还要调用拷贝构造函数
return *this;
}
// d1++ -> d1.operator++(&d1,0);
Date Date::operator++(int)//用参数标志后置++
{
Date tmp(*this);
*this += 1;
return tmp;
}
Date& Date::operator--()
{
*this -= 1;
return *this;
}
Date Date::operator--(int)
{
Date tmp(*this);
*this -= 1;
return tmp;
}