一、引言
类、对象与运算符的重载,是C++的入门基础,同时也是C++的重点模块,是后面面向对象编程、STL等内容的核心,本文将在类、对象、运算符重载的基础上,进一步实现类、对象、运算符重载三者的综合应用,完成一个日期类项目,该项目包括了对日期的加减、日期大小的比较、求两个日期的相差天数等函数的实现,该项目综合应用了类、对象、运算符重载三大板块的内容,应用性很强,适合广大C++学者学习和实现的一个小项目。
目录
二、项目实现
1、项目文件

(1)
我们将项目的实现分为3个文件,Date.h头文件、Date.cpp实现文件、Test.cpp测试文件。
Date.h头文件主要用于函数的声明、以及部分函数的实现。
Date.cpp实现文件用于实现Date.h头文件中的函数。
Test.cpp测试文件用于测试Date.cpp文件实现的函数。
2、日期类成员
(1)成员变量
#pragma once
#include<iostream>
using namespace std;
#include<assert.h>
class Date
{
private:
int _year;
int _month;
int _day;
}
在Date.h头文件中声明日期Date类的成员变量,日期类的成员变量包括年_year、月_month、日_day,在Date类中一般为类私有,为private类型,一般不允许外界访问。
(2)成员函数
#pragma once
#include<iostream>
using namespace std;
#include<assert.h>
class Date
{
//友元函数声明
friend ostream& operator<<(ostream& out,const Date& d);
friend istream& operator>>(istream& in, Date& d);
public:
Date(int year = 1, int month = 1, int day = 1);
void print()const;
bool Checkdate()const;
//默认是inline
int Getmonthday(int year, int month)const
{
assert(month > 0 && month < 13);
static int montharray[13] = { -1,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];
}
Date operator+(int day)const;
Date& operator+=(int day);
Date& operator-=(int day);
Date operator-(int day)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;
bool operator!=(const Date& d)const;
//++d
Date& operator++();
//d++
Date operator++(int);
//--d
Date& operator--();
//d--
Date operator--(int);
int operator-(const Date& d)const;
//void operator<<(ostream& out);
//非常量对象
Date* operator&()
{
//return this;
return (Date*)0x20250930;
}
//常量对象
const Date* operator&()const
{
//return this;
return (Date*)0x20251001;
}
private:
int _year;
int _month;
int _day;
};
ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& in, Date& d);
日期类Date的成员函数较多,包括了对日期的加减、日期的大小比较关系、求两个日期的相差天数等等一系列函数,可参考上图Date.h头文件的函数声明,这些成员函数为public类型,允许外界访问,由于函数较多,这里不逐一展开说明,下文实现这些函数时将详细展开介绍。
3、函数实现
(1)构造函数
构造函数声明(Date.h)
Date(int year = 1, int month = 1, int day = 1);
日期构造函数的参数为年year、月month、日day,三个参数我们都设为缺省参数,默认值为1。
构造函数实现(Date.cpp)
#include"Date.h"
Date::Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
日期构造函数在Date.h头文件中声明,实现在Date.cpp实现文件中完成,Date.cpp实现文件需包含Date.h头文件的函数声明,日期构造函数与下面要实现的成员函数都类似,日期构造函数为成员函数,在类外实现需指明所在类域Date,函数实现只需将参数year、month、day的值赋值给成员变量_year、_month、_day即可。
(2)print函数
print函数声明(Date.h)
void print()const;
print函数用于打印日期信息,无返回类型,const用于修饰对象,使得对象只读不可写。
print函数实现(Date.cpp)
//void Date::print(const Date*const this);
void Date::print()const
{
cout << _year << "/" << _month << "/" << _day << endl;
}
print函数实现只需将成员变量_year、_month、_day以_year/_month/_day的日期形式打印出来即可,即cout<<_year<<"/"<<_month<<"/"<<_day<<endl,const用于修饰对象,相当于const Date*const this,使得对象只读不能写。
print函数测试(Test.cpp)
(2)
print函数测试在Test.cpp测试文件中完成,如图(2)所示,先调用构造函数完成d1的初始化,即Date d1(2025,10,1),随后直接调用成员函数print,即d1.print(),屏幕上显示2025/10/1,表明print函数测试成功,同时也表明构造函数Date测试成功。
(3)Getmonthday函数
Getmonthday函数声明和定义(Date.h)
//默认是inline
int Getmonthday(int year, int month)const
{
assert(month > 0 && month < 13);
static int montharray[13] = { -1,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];
}
Getmonthday用于获取当前月份的天数,Getmonthday与前面函数不同在于Getmonthday函数声明与定义都在Date.h头文件中完成,之所以不分离Getmonthday函数的声明与定义,是因为在类中实现的函数默认为inline内联函数,内联函数会在函数调用处直接展开,不需创建函数栈帧,可以提高函数调用的效率,由于Getmonthday函数在后续函数实现中经常要调用,频繁调用且代码量并不大,因此我们选择在类中实现该函数。
Getmonthday函数参数为年year、月month,返回该月的天数,const修饰对象,只读不可写,assert断言确保月份有效,用一维数组存储每个月份的天数,该数组有13个元素,数组首元素设为-1,后面12个元素依次为1~12月的天数,可知数组下标所对应的元素即为该下标作为月份时的天数,数组用static修饰,存储在静态区,为全局变量,可多次调用,之后考虑2月这一特殊月份,当年份为闰年时,2月有29天,我们采用if进行条件判断,当月份为2且为闰年时,返回29,一般情况下,则返回该月份作为下标时对应的元素,即为该月份的天数。
Getmonthday函数测试(Test.cpp)
(3)
在Test.cpp中测试Getmonthday函数,以d1为测试样例,求d1的月份天数,Getmonthday为d1的成员函数,即d1.Getmonthday(2025,10),ret用来接收d1.Getmonthday(2025,10)的返回值,结果为31,测试结果正确,Getmonthday函数测试通过。
(4)Checkdate函数
Checkdate函数声明(Date.h)
bool Checkdate()const;
Checkdate函数用于判断日期是否合法,返回类型为bool类型,const用于修饰对象,可读不可写。
Checkdate函数实现(Date.cpp)
bool Date::Checkdate()const
{
if (_month < 1 || _month>12 || _day<1 || _day>Getmonthday(_year, _month))
{
return false;
}
else
{
return true;
}
}
Checkdate函数实现即判断月份是否在1~12之间,以及日期是否大于0且不得超过该月的天数,若不符合条件,则返回false,反之则返回true。
Checkdate函数也可加在构造函数中,用来判断构造函数的日期是否非法。
#include"Date.h"
Date::Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
if (!Checkdate())
{
cout << "非法日期:";
print();
}
}
Checkdate函数测试(Test.cpp)
(4)
在Test.cpp文件中对Checkdate函数进行测试,首先构造函数对d1进行初始化,即Date d1(2025,10,32),为非法日期,随后调用d1的成员函数Checkdate进行判断,即d1.Checkdate(),ret接收返回值,结果显示日期为非法日期,ret==0,表明测试结果正确,Checkdate函数测试通过。
4、运算符重载函数
(1)operator+=重载
operator+=重载函数声明(Date.h)
Date& operator+=(int day);
operator+=重载函数用于计算日期加上天数后的日期,函数参数为要加的天数,返回该日期的引用,选择返回值也是可以的,返回引用可以减少拷贝。
operator+=重载函数实现(Date.cpp)
Date& Date::operator+=(int day)
{
_day += day;
while (_day > Getmonthday(_year, _month))
{
_day -= Getmonthday(_year, _month);
_month++;
if (_month == 13)
{
_year++;
_month = 1;
}
}
return *this;
}
operator+=函数实现先对成员变量_day+=day,之后再判断_day是否超过该月的天数,通过Getmonthday函数判断,若超过该月的天数,_day则向_month发生进位,_month++,_day需减掉该月的天数,还需考虑一种特殊情况,当_month==12时,这时_month++,则_month==13,这时_month向_year进位,_year++,_month置为1,while循环结束条件为_day不再大于该月的天数,循环结束,由于+=运算符,故返回this指针所指向的对象,即return *this,选择引用返回,相比传值返回,可以减少拷贝。
operator+=重载函数测试(Test.cpp)
(5)
对operator+=重载函数进行测试,构造函数先初始化d1,即Date d1(2025,10,1),对运算符+=重载后,就可直接使用+=运算符即可,无需使用函数名operator+=来完成调用,即d1+=100,再调用成员函数print()查看最后的结果,结果显示为2026/1/9,经验证后结果正确,operator+=函数测试通过。
(2)operator+重载
operator+重载函数声明(Date.h)
Date operator+(int day)const;
operator+重载函数的参数与operator+=一致,都为要加的天数day,const用于修饰this指针指向的对象,使对象可读不可写,operator+与operator+=不同在于返回对象的不同,operator+=会改变运算对象,而operator+不会改变运算对象,operator+运算的结果会保存在一个局部变量中,最后会返回该局部变量的拷贝,注意这里不能返回引用,因为operator+的结果保存在一个局部变量中,当函数执行结束时,该局部变量也会随之销毁,若返回引用,即返回该局部变量的引用,但该局部变量在函数结束时已被销毁,该引用就为野引用了,因此这里就不能返回引用了,只能传值返回,返回该临时变量的拷贝。
operator+函数实现(Date.cpp)
Date Date::operator+(int day)const
{
Date tmp = *this;
tmp += day;
return tmp;
}
operator+函数实现与operator+=函数实现类似,不同在于operator+函数需先创建一个临时变量tmp,将*this拷贝到tmp中,这是为了确保不改变*this的内容,而operator+=会改变*this的内容,这是operator+与operator+=的一大区别,operator+=函数我们前面已经实现过了,随后对tmp+=day即可,最后传值返回tmp的拷贝,这一过程只改变tmp,*this没有改变。
operator+函数测试(Test.cpp)
(6)
在Test.cpp文件中对operator+函数进行测试,先构造并初始化d1,即d1(2025,10,1),再对d2进行初始化,将d1+10拷贝给d2,最后调用print函数打印d1、d2,d1为2025/10/1,可知d1的内容没有改变,d2为2025/10/11,与d1+10的结果一致,operator+函数测试通过。
(3)operator-=重载
operator-=重载函数声明(Date.h)
Date& operator-=(int day);
operator-=函数声明和实现与前面的operator+=函数类似,函数参数为要减的天数,返回类型也为引用,可以减少拷贝。
operator-=重载函数实现(Date.cpp)
Date& Date::operator-=(int day)
{
if (day < 0)
{
return *this += (-day);
}
_day -= day;
while(_day <= 0)
{
--_month;
if (_month == 0)
{
_year--;
_month = 12;
}
_day += Getmonthday(_year, _month);
}
return *this;
}
operator-=重载函数实现与operator+=函数实现类似,当day>0时,先_day-=day,天数相减,再判断相减后的日期是否小于0,若日期小于0,则需借位,_day向_month借位,_month--,_day加上对应月份的天数,这里也需考虑一种特殊情况,当_month--为0时,这时_month需向_year借位,_year--,_month置为12,while循环结束条件为当_day>0时结束循环,当day小于0时,此时_day-=day,可转化为_day+=(-day),因此当day<0时,直接转化为*this+=(-day)即可,最后返回this指针所指向的对象,即return *this。
operator-=重载函数测试(Test.cpp)
(7)
operator-=重载函数测试,先构造并初始化对象d1,即Date d1(2025,10,11),再对d1-=10,调用成员函数print查看结果,可知d1变为2025/10/1,与d1-=10的结果一致,故operator-=重载函数测试通过。
实现了operator-=重载函数,可以对operator+=优化一下,当day小于0时,operator+=day可转化为operator-=(-day),即*this-=(-day)。
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;
}
(4)operator-重载
operator-重载函数声明(Date.h)
Date operator-(int day)const;
operator-重载函数声明与实现也可类比operator+,operator-函数参数为day,表示要减的天数,const用于修饰对象,使对象可读不可写,这里同样需要注意operator-与operator+一样,也只能传值返回,不能传引用返回。
operator-重载函数实现(Date.cpp)
Date Date::operator-(int day)const
{
Date tmp = *this;
tmp -= day;
return tmp;
}
operator-重载函数实现与operator+实现也类似,也是先将this指针所指向的对象拷贝到tmp中,保证*this不被修改,之后利用上面已实现的operator-重载函数,对tmp减去day即可,即tmp-=day,最后返回tmp,return tmp即可。
operator-重载函数测试(Test.cpp)
(8)
operator-重载函数测试:先构造并初始化对象d1,即Date d1(2025,10,11),再将d1-10拷贝到d2中,调用成员函数print查看d1、d2的内容,d1为2025/10/11,d1没有发生改变,d2为2025/10/1,与d1-10的结果一致,operator-重载函数测试通过。
(5)operator<重载
operator<重载函数声明(Date.h)
bool operator<(const Date& d)const;
operator<重载用于判断两个日期的大小关系,函数的返回类型为bool,<为双目运算符,左侧运算对象传给成员函数的第一个函数参数this指针所指向的对象,this指针在函数参数中隐式表示,右侧运算对象传右侧对象的引用,也可传值,传引用可以减少拷贝,const Date& d,该const用于修饰右侧运算对象,只读不能写,bool operator<(const Date& d)const 该const用于修饰this指针指向的对象,也是只读不能写。
operator<重载函数实现(Date.cpp)
bool Date::operator<(const Date& d)const
{
if (_year < d._year)
{
return true;
}
else if (_year == d._year)
{
if (_month < d._month)
{
return true;
}
else if (_month == d._month)
{
return _day < d._day;
}
}
return false;
}
operator<重载函数实现即比较两个日期的大小关系,左侧运算对象为this指针指向的对象,右侧运算对象传该对象的引用,相比传值可以减少拷贝,先比较两个日期的年份,若*this的年份小于d的年份,则*this<d,返回true,另一种情况,当二者年份相等时,继续比较二者的月份,若*this的月份小于d的月份,则*this<d,若二者年月都相等,则继续比较二者的_day,_day小的则日期小。以上情况除外,剩下的情况*this均大于d,不符合<的条件,返回false。
operator<重载函数测试(Test.cpp)
(9)
对operator<重载函数进行测试,先构造并初始化d1、d2,即Date d1(2025,10,11),Date d2(2025,10,1),然后对d1、d2进行比较,ret接收d2<d1的返回值,ret=1,可知结果正确,operator<重载函数测试通过。
(6)operator==重载
operator==重载函数声明(Date.h)
bool operator==(const Date& d)const;
operator==重载函数用于判断两个日期是否相等,声明与operator<类似,返回类型、函数参数与operator<一致,const用于修饰this指针指向的对象,使得对象可读不可写。
operator==重载函数实现(Date.cpp)
bool Date::operator==(const Date& d)const
{
return _year == d._year
&& _month == d._month
&& _day == d._day;
}
operator==重载函数实现相比operator<较为简单,判断两个日期是否相等,只需判断两个日期对应的年_year、月_month、日_day是否都相等,若三者都相等,则两个日期相等,反之则不相等。
operator==重载函数测试(Test.cpp)
(10)
operator==重载函数测试:先构造并初始化d1、d2,即Date d1(2025,10,11),Date d2(2025,10,1),ret接收d1==d2的返回值,ret==0,与d1!=d2一致,结果正确,operator==重载函数测试通过。
(7)operator<=重载
operator<=重载函数声明(Date.h)
bool operator<=(const Date& d)const;
operator<=重载函数声明与operator<的返回类型、函数参数一致,const用于修饰this指针指向的对象,使得对象可读不可写。
operator<=重载函数实现(Date.cpp)
bool Date::operator<=(const Date& d)const
{
return *this < d || *this == d;
}
有了前面的operator<与operator==重载函数,实现operator<=重载就简单了,只需满足二者当中的一种即可,即*this<d || *this==d,这样就实现了operator<=重载函数。
operator<=重载函数测试(Test.cpp)
(11)
operator<=重载函数测试:构造并初始化d1、d2、d3,即Date d1(2025,10,11),Date d2(2025,10,1),Date d3(2025,10,11),ret1接收d2<=d1的返回值,ret2接收d3<=d1的返回值,ret1、ret2均为1,与d2<=d1、d3<=d1一致,结果正确,operator<=重载函数测试通过。
(8)operator>重载
operator>重载函数声明(Date.h)
bool operator>(const Date& d)const;
operator>重载函数声明与operator<类似,可参考上文operator<重载函数的声明说明,这里就不再赘述了。
operator>重载函数实现(Date.cpp)
bool Date::operator>(const Date& d)const
{
return !(*this <= d);
}
operator>重载函数实现也可借助前面已实现的operator<=函数,对operator<=取反,即!(*this<=d),就实现了operator>重载函数。
operator>重载函数测试(Test.cpp)
(12)
operator>重载函数测试:先构造并初始化d1、d2,即Date d1(2025,10,11),Date d2(2025,10,1),ret1接收d1>d2的返回值,ret1==1,与d1>d2一致,结果正确,operator>重载函数测试通过。
(9)operator>=重载
operator>=重载函数声明(Date.h)
bool operator>=(const Date& d)const;
operator>=重载函数声明与operator<函数声明类似,可参考operator<重载函数的函数声明。
operator>=重载函数实现(Date.cpp)
bool Date::operator>=(const Date& d)const
{
return !(*this<d);
}
operator>=重载函数实现可借助前面实现的operator<重载运算符来进行判断,对operator<取反,即!(*this<d),就实现了operator>=重载函数。
operator>=重载函数测试(Test.cpp)
(13)
对operator>=重载函数进行测试:先构造并初始化d1、d2、d3,即Date d1(2025,10,11),
Date d2(2025,10,1),Date d3(2025,10,11),再将d1>=d2,d1>=d3的返回值传给ret1、ret2,ret1与ret2的值均为1,与d1>=d2、d1>=d3一致,结果正确,operator>=重载函数测试通过。
(10)operator!=重载
operator!=重载函数声明(Date.h)
bool operator!=(const Date& d)const;
operator!=重载函数声明与operator<函数声明类似,可参考operator<的函数声明。
operator!=重载函数实现(Date.cpp)
bool Date::operator!=(const Date& d)const
{
return !(*this == d);
}
operator!=重载函数实现也可借助前面已实现的operator==重载运算符来进行判断,对operator==取反,即!(*this==d),就实现了operator!=重载函数。
operator!=重载函数测试(Test.cpp)
(14)
operator!=重载函数测试:先构造并初始化对象d1、d2,即Date d1(2025,10,11),Date d2(2025,10,1),ret1接收d1!=d2的返回值,ret==1,与d1!=d2一致,结果正确,operator!=重载函数测试通过。
(11)operator++()重载
operator++()重载函数声明(Date.h)
//++d
Date& operator++();
operator++()函数实现前置++运算符的重载,函数选择引用返回,也可以传值返回,传引用返回可以减少拷贝。
operator++()重载函数实现(Date.cpp)
Date& Date::operator++()
{
*this += 1;
return *this;
}
operator++()重载函数实现利用前面已实现的重载运算符operator+=,即*this+=1,返回this指针指向的对象,return *this即可。
operator++()重载函数测试(Test.cpp)
(15)
operator++()重载函数测试:先构造并初始化对象d1,即Date d1(2025,10,1),随后将++d1拷贝到对象d2,调用成员函数print查看d1、d2,d2变为2025/10/2,与++d1结果一致,operator++()重载函数测试通过。
(12)operator++(int)重载
operator++(int)重载函数声明(Date.h)
//d++
Date operator++(int);
operator++(int)重载函数实现后置++运算符的重载,相比前置++(operator++())多了一个int形参,这个int形参没有实际意义,只是为了区别前置++与后置++,函数返回需传值返回,不能引用返回,因为后置++的结果是计算之前的值,因此需要先拿一个局部变量保存计算前的值,然后返回该局部变量,若返回引用,则返回该局部变量的引用,由于局部变量在函数结束时自动销毁,则该引用就变为野引用,所以只能传值返回,返回该局部变量的拷贝。
operator++(int)重载函数实现(Date.cpp)
Date Date::operator++(int)
{
Date tmp = *this;
*this += 1;
return tmp;
}
operator++(int)函数实现借助前面实现的operator+=重载运算符,创建一个临时变量tmp,将*this拷贝到tmp中,随后*this+=1,最后返回tmp的拷贝,就实现后置++(operator++(int))重载运算符。
operator++(int)重载函数测试(Test.cpp)
(16)
operator++(int)重载函数测试:构造并初始化对象d1,即Date d1(2025,10,1),再将d1++拷贝到对象d2中,调用成员函数print查看d1、d2,d1变为2025/10/2,d2为2025/10/1,与d1++结果一致,operator++(int)重载函数测试通过。
(13)operator--()重载
operator--()重载函数声明(Date.h)
//--d
Date& operator--();
operator--()函数声明与operator++()函数声明类似,operator--()实现前置--运算符的重载,可参考operator++()的函数声明。
operator--()重载函数实现(Date.cpp)
Date& Date::operator--()
{
*this -= 1;
return *this;
}
operator--()重载函数实现借助前面已实现的operator-=重载运算符,对*this-=1,返回this指向的对象,return *this即可。
operator--()重载函数测试(Test.cpp)
(17)
operator--()重载函数测试:构造并初始化对象d1,即Date d1(2025,10,1),再将--d1拷贝到d2,调用成员函数print查看d1、d2,d1、d2都为2025/9/30,与--d1的结果一致,故operator--()重载函数测试通过。
(14)operator--(int)重载
operator--(int)重载函数声明(Date.h)
//d--
Date operator--(int);
operator--(int)重载函数声明与operator++(int)函数声明类似,operator--(int)实现后置--运算符的重载,可参考operator++(int)的函数声明。
operator--(int)重载函数实现(Date.cpp)
Date Date::operator--(int)
{
Date tmp = *this;
*this-=1;
return tmp;
}
operator--(int)函数实现借助前面已实现的operator-=重载运算符,先将*this拷贝到临时变量tmp中,再对*this-=1,最后返回tmp的拷贝,即return tmp。
operator--(int)重载函数测试(Test.cpp)
(18)
operator--(int)重载函数测试:构造并初始化对象d1,即Date d1(2025,10,1),再将d1--拷贝到对象d2中,调用成员函数print查看d1、d2,d1为2025/9/30,d2为2025/10/1,与d1--的结果一致,operator--(int)重载函数测试通过。
(15)求两个日期相差天数(operator-)
函数声明(Date.h)
int operator-(const Date& d)const;
operator-该函数用于求两个日期的相差天数,函数返回值为两个日期相差的天数,第一个运算对象为this指针所指向的对象,第二个运算对象通过传该对象的引用,可以减少拷贝,const Date& d的const用于修饰该对象只读不能写,int operator-(const Date& d)const ,该const用于修饰this指针指向的对象,也是使对象只读不能写。
函数实现(Date.cpp)
int Date::operator-(const Date& d)const
{
int flag = 1;
int n = 0;
Date max = *this;
Date min = d;
if (*this<d)
{
min = *this;
max = d;
flag = -1;
}
while (min != max)
{
min++;
n++;
}
return flag * n;
}
函数实现中定义了一个符号标志位flag,flag初始化为1,整形变量n初始化为0,采用假设法,先假设*this为较大的日期,随后if语句进行判断,若*this<d,则将d赋值给max,*this赋值给min,这时*this-d小于0,符号位flag置为-1,这样max就是较大的日期,min就是较小的日期,通过while循环计算出两者相差的天数,当min!=max时,min++,n++,直到min==max,此时的n就是两者相差的天数,最后返回n与符号位flag的乘积,就是两个日期相差的天数。
函数测试(Test.cpp)
(19)
对函数进行测试:先构造并初始化对象d1、d2,即Date d1(2025,10,1),Date d2(2025,7,5),ret接收d1-d2的返回值,即二者相差的天数,ret==88,经验证结果正确,函数测试通过。
(16)operator&重载
operator&重载函数一般不需要我们自己来实现,编译器默认会帮我们实现。除非在一些特殊情况,例如我们不想让他人获取成员的地址,这时我们就可以自己实现一个operator&函数,然后胡乱返回一个地址,如下图代码所示:
operator&函数声明和实现(Date.h)
//非常量对象
Date* operator&()
{
//return this;
return (Date*)0x20250930;
}
//常量对象
const Date* operator&()const
{
//return this;
return (Date*)0x20251001;
}
两个operator&函数,一个用const修饰的operator&,是用来获取常量对象的地址,不加const修饰的operator&获取非常量对象的地址,正常情况下二者都返回this指针,但如果不想让他人取到地址,则只需胡乱返回一个地址即可。
operator&函数测试(Test.cpp)
(20)
如上图,构造并初始化d1、d2,d2用const修饰,为常量对象,我们对&进行了重载,这时d1、d2的地址就变为了我们自己设置的地址,他人无法得知d1、d2的正确地址,operator&函数测试通过。
(17)operator<<重载
operator<<重载函数声明(Date.h)
ostream& operator<<(ostream& out, const Date& d);
//友元函数声明
friend ostream& operator<<(ostream& out,const Date& d);
重载<<和>>需要重载为全局函数,因为若重载为成员函数,this指针默认抢占了第一个形参位置,第一个形参位置是左侧运算对象,调用时就变成了对象<<cout,不符合使用习惯和可读性。重载为全局函数,由于<<和>>是ostream和istream的对象,因此把ostream/istream放到第一个形参位置就可以了,第二个形参位置为类类型对象,传引用可以减少拷贝,const修饰对象可读不可写。operator<<重载函数的返回类型为ostream&,方便连续输出,引用返回可以减少拷贝。
这里需要注意的是operator<<重载函数不为成员函数,一般情况下不能访问类中的成员变量_year、_month、_day,需要在类中加上友元函数声明,函数才能访问类中的成员变量,即在函数声明前加上friend关键字,即friend ostream& operator<<(ostream& out,const Date& d)。
operator<<重载函数实现(Date.cpp)
ostream& operator<<(ostream& out, const Date& d)
{
out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
return out;
}
operator<<重载函数实现即将日期对象的成员变量_year、_month、_day按年月日的方式依次输出,返回cout的引用,方便连续输出。
operator<<重载函数测试(Test.cpp)
(21)
operator<<重载函数测试:先构造并初始化对象d1、d2,即Date d1(2025,10,1),Date d2(2025,10,2),再对operator<<进行测试,即cout<<d1<<d2<<endl,结果为2025年10月1日、2025年10月2日,结果正确,operator<<重载函数测试通过。
(18)operator>>重载
operator>>重载函数声明(Date.h)
istream& operator>>(istream& in, Date& d);
friend istream& operator>>(istream& in, Date& d);
operator>>重载函数声明与operator<<类似,函数返回类型为istream&,为cin的引用,方便连续输入,将istream类的对象放到第一个形参位置,符合习惯和可读性,第二个形参为类对象的引用,传引用可以减少拷贝,这里需要注意的是operator>>重载函数不为成员函数,因此一般情况下不能访问类对象的成员变量_year、_month、_day,我们需要在类中加上友元函数声明,函数才能访问类中的成员变量,即在函数声明前加上friend关键字,即friend istream& operator>>(istream& in,Date& d);
operator>>重载函数实现(Date.cpp)
istream& operator>>(istream& in, Date& d)
{
while (1)
{
cout << "请依次输入年月日:>";
in >> d._year >> d._month >> d._day;
if (!d.Checkdate())
{
cout << "输入日期非法";
d.print();
cout << "请重新输入!"<<endl;
}
else
{
break;
}
}
return in;
}
operator>>重载函数实现依次输入年月日,即in>>d._year>>d._month>>d._day,可检查输入的日期是否合法,调用成员函数Checkdate()进行判断,若非法,则需重新输入,while循环继续下一次的输入,若日期合法,则break跳出循环,返回cin的引用,方便连续输入。
operator>>重载函数测试(Test.cpp)
(22)
operator>>重载函数测试:先构造并初始化对象d1,d2,Date d1,d2,再依次输入d1、d2,cin>>d1>>d2,最后输出查看d1、d2内容,即cout<<d1<<d2<<endl,输入d1为2025 10 1,d2为2025 10 2,d1、d2的输出分别为2025年10月1日,2025年10月2日,可知与输入内容一致,operator>>重载函数测试通过。
三、结语
至此,这个日期类项目的全部函数和重载运算符均已全部实现,该日期类项目综合应用了类、对象、运算符重载三大板块的核心内容,综合性较强,涉及面广,通过这个看似简单的日期类项目,可以看出,在C++中,简单的背后往往隐藏着复杂的细节,从各种的运算符重载到流操作的支持,每一步的实现往往都不简单,需要考虑很多细节,我们实现的这个日期类项目,将数据和操作完美地捆绑在一起,通过运算符重载,让日期操作像操作基本数据类型一样直观,C++的学习,就是这样一个不断重构、拓展和深化的过程,这个项目的实现也很好地证明了这一观点。






















1875

被折叠的 条评论
为什么被折叠?



