前言
通过日期类的实行可以帮助我们更好的了解掌握之前类和对象学的6个默认成员函数(尤其是赋值运算符重载和普通对象和const对象的理解)
一、日期类的实现
- 私有成员部分:
_year、_month、_day分别用来存储日期的年、月、日信息。
- 成员函数部分:
static int GetMonthDay(int year, int month);
GetMonthDay函数用于判断当前月份是否为闰年,依据闰年的判断规则(能被 4 整除但不能被 100 整除,或者能被 400整除);并且根据月份对应的天数以及是否闰年等情况判断日的取值
构造函数,析构函数,拷贝构造,赋值构造函数,打印函数
还有一系列重载的成员函数
- 构造函数部分:
全缺省构造函数可以根据传入的年、月、日值来初始化日期对象,同时会调用assert来确保传入的日期是合法的,若不合法程序会报错终止。
- 运算符重载部分:
- 重载了 << 和 >> 运算符,使得可以方便地将日期对象输出 or 输入到输出流(比如cin,cout)中,输出 or 输入格式为年-月-日。
- 重载了+和-运算符,分别实现了日期对象增加或减少指定天数的功能,在运算过程中会根据每个月的天数以及是否闰年等情况,对日期进行合理的调整,确保最终得到的结果是合法的日期。
- 重载了 ++ 和 - - 运算符
- 重载了< <= > >= == != 运算符
二、具体实现
1. Date.h
代码如下(示例):
#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);
public:
//构造函数
//一般都放在成员函数里,做内联函数,这里规范一下声明定义分离开写
Date(int year = 2024, int month = 1, int day = 1);
//拷贝构造函数
//d2(d1)
//Date(const Date& d)
//{
// cout << "Date(const Date& d)" << endl;
// this->_year = d._year;
// this->_month = d._month;
// this->_day = d._day;
//}
//赋值构造函数
//Date& operator=(const Date& d)
//{
// if (this != &d)
// {
// _year = d._year;
// _month = d._month;
// _day = d._day;
// }
// return *this;//*this出了作用域还在,可以用引用返回
//}
void print(/*Date* this*/) const
{
cout << _year << "年" << _month << "月" << _day << "日"<< endl;
}
static int GetMonthDay(int year, int month);
//重载这两个下面都可以复用
bool operator<(const Date& x)const;
bool operator==(const Date& x)const;
bool operator<=(const Date& x)const;
bool operator>(const Date& x)const;
bool operator>=(const Date& x)const;
bool operator!=(const Date& x)const;
Date& operator+=(int day);
Date operator+(int day)const;
Date& operator-=(int day);
Date operator-(int day)const;
Date& operator++();
Date operator++(int);//后置
Date& operator--();
Date operator--(int);
/*C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递
编译器自动传递*/
//日期类相减
int operator-(const Date& d)const;
//void operator<<(ostream& out);
// 流插入不能写成成员函数
// 因为Date对象默认占用第一个参数,就是做了左操作数
// 写出来就一定是下面这样子,不符合使用习惯
//d1 << cout; // d1.operator<<(cout);
//java一般这样使用让全局函数获取成员变量
/*int Getyear()
{
return _year;
}*/
private:
int _year;
int _month;
int _day;
};
//流插入运算符重载
ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& in, Date& d);
2. Date.cpp
代码如下(示例):
#include"Date.h"
Date::Date(int year, int month, int day)
{
if (month > 0 && month <= 12
&& day > 0 && day <= GetMonthDay(year, month))//还没有初始化不用_day
{
this->_year = year;
this->_month = month;
this->_day = day;
}
else
{
cout << "日期非法" << endl;
assert(false);
}
}
int Date::GetMonthDay(int year, int month)
{
//频繁调用,太浪费,直接放在静态区里
static int monthArray[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0))
{
return 29;
}
return monthArray[month];
}
bool Date::operator==(const Date& x)const
{
return _year == x._year && _month == x._month && _day == x._day;
}
复用即可
bool Date::operator!=(const Date& x)const
{
return !(*this == x);
}
bool Date:: operator<(const Date& x)const
{
if (_year < x._year)
{
return true;
}
else if (_year == x._year && _month < x._month)
{
return true;
}
else if (_year == x._year && _month == x._month && _day < x._day)
{
return true;
}
return false;
}
bool Date:: operator<=(const Date& x)const
{
return *this < x || *this == x;
}
bool Date::operator>(const Date& x)const
{
复用即可
return !(*this <= x);
}
bool Date::operator>=(const Date& x)const
{
//return *this > x || *this == x;
return !(*this < x);
}
Date& Date::operator+=(int day)//返回值是引用,支持连续赋值,*this出了作用域不销毁
{
if (day < 0)
{
return *this -= -day;
}
this->_day += day;
while (_day > GetMonthDay(_year, _month))
{
_day -= GetMonthDay(_year, _month);
_month++;
if (_month > 12)
{
_month = 1;
_year++;
}
}
return *this;
}
//+复用+=合适,不会多次拷贝构造,如果+=复用+会多调用2次拷贝构造效率低下
Date Date::operator+(int day)const
{
Date tmp(*this);
tmp += day;
return tmp;
}
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)const
{
Date tmp(*this);
tmp -= day;
return tmp;
}
Date& Date::operator++()//前置++
{
*this += 1;
return *this;
}
//增加这个int参数不是为了具体的值,(int i)如果参数无意义可以不写,只是为了占位,区分前置++和后置++
//跟前置++构成重载
Date Date::operator++(int)//后置++
{
Date tmp(*this);
*this += 1;
return tmp;
}
//运算符重载是为了让类的对象(自定义类型)像内置类型一样使用,但是不能改变内置类型的优先级和结合性
//函数重载是支持函数名相同,但是参数列表不同的情况下,可以定义多个同名函数
//两个重载的运算符可以构成函数重载??? ---可以
//他们两个本身也是普通函数,只是他们的函数名比较特殊
//对于内置类型,前置++和后置++效率一样
//对于自定义类型,前置++效率高于后置++,因为后置++多了2次拷贝构造,传值返回还要创建一个对象
Date& Date::operator--()
{
*this -= 1;
return *this;
}
Date Date::operator--(int i)//参数可写可不写,因为参数没有实际意义
{
Date tmp(*this);
*this -= 1;
return tmp;
}
//日期相减
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 count = 0;
while (min != max)
{
++min;
++count;
}
return count * flag;
}
//流插入 or 流提取运算符重载不能写在类里,因为默认左操作数是this指针,而流插入运算符左操作数是cout,所以不能写在类里
//void Date::operator<<(ostream& out)
//{
// out << _year << "-" << _month << "-" << _day << endl;
//}
// 写成全局函数
//流插入运算符重载
ostream& operator<<(ostream& out, const Date& d)
{
out << d._year << "-" << d._month << "-" << d._day << endl;
return out;
}
istream& operator>>( istream& in, Date& d)//要提取他的内容也要改他的状态值
{
int year, month, day;
in >> year >> month >> day;
if (month > 0 && month <= 12
&& day > 0 && day <= Date::GetMonthDay(year, month))
{
d._year = year;
d._month = month;
d._day = day;
}
else
{
cout << "日期非法" << endl;
assert(false);
}
return in;
}
3. test.cpp
代码如下(示例):
#include"Date.h"
void test1()
{
Date d1(2024, 1, 1);
d1 += 100;
d1.print();
Date d2(2024, 1, 1);
d2 + 100;
d2.print();
Date d3 = d2 + 100;
d3.print();
//用一个已经存在的对象初始化另一个对象 --- 构造函数
Date d4 = d2;/*等价于Date d4(d2); --拷贝构造*/
//已经存在的两个对象之间复制拷贝 --- 运算符重载函数
d4 = d1; /*等价于d4.operator=(d1); --赋值构造*/
//+=用引用返回为了支持连续赋值
int i = 0;
int j = 0;
j += i += 10;
}
void test2()
{
Date d1(2024, 1, 1);
d1++;//d1.operator++(&d1,0);0和1是编译器固定传的;
d1.print();
++d1;//d1.operator++(&d1);
d1.print();
//对于内置类型,前置++和后置++效率一样
//对于自定义类型,前置++效率高于后置++
}
void test3()
{
Date d1(2024, 1, 1);
Date d2(2024, 1, 1);
d1 < d2;//内置类型直接转换成指令,编译器知道怎么处理
//编译完后,直接转换成对应的指令cmp这种
int i = 1, j = 2;
i < j;
}
void test4()
{
Date d1(2023, 5, 5);
//d1 - 30;
d1.print();
Date d2 = d1 - 50;
d2.print();
}
void test5()
{
Date d1(2025, 1, 1);
Date d2(1964, 10, 1);
cout << d1 - d2 << endl;
cout << d2 - d1 << endl;
}
void test6()
{
Date d1(2025, 1, 1);
Date d2(1964, 10, 1);
//流插入
cout << d1;//operator<<(cout,d1);
cout << d1 << d2;//operator<<(operator<<(cout,d1),d2);
//d1 << cout;//有些类似于cout.operator<<(d1);别扭的不行
Date d3(2025, 1, 1);
Date d4(2025, 1, 6);
cout << d4 << d3 << d1 << endl;//把输入的东西插入到终端
Date d1;
Date d2;
cin >> d1 >> d2;//从终端输入的东西提取出来
d1.print();
d2.print();
}
void test7()
{
Date d1(2025, 1, 6);
d1.print();
const Date d2(2025, 1, 7);
d2.print();
//成员函数后面加const,修饰*this
//普通对象和const对象都可以调
// 注:
//但是要修改的对象成员变量的函数不能加
//只要成员函数内部不修改成员变量,都应该加const
//Eg:operator+=
//this->_day += day;
//d1 < d2//这里因为d2的对象是const所以能过,反过来就不行了
//d2 < d1
}
int main()
{
//test1();
//test2();
//test3();
//test4();
//test5();
test6();
test7();
return 0;
}
标签:const,对象,operator,month,int,日期,应用,Date,day
From: https://blog.csdn.net/2301_79262802/article/details/144967275