如下是一个日期类:
class Date
{
public:Date(int year = 2023, int month = 10, int day = 1){_year = year;_month = month;_day = day;if (_month < 1 || month > 12 || _day < 1 || _day > GetMonthDay(_year, _month)){cout << "日期不规范" << endl;//exit(-1); 终止程序}}//拷贝构造函数Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}void print() const //const 放在这里,指的是this指针为const Date*类型,这样就可以让const Date类型进行print了{cout << _year << "/" << _month << "/" << _day << endl;}int GetMonthDay(int year, int month)//获取某面某月的天数{//加static,可以省去每次访问时都开辟数组空间。static int MonthArray[] = { 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];}//赋值运算符//返回类型为Date,支持连续赋值Date& operator=(const Date& d){_year = d._year;_month = d._month;_day = d._day;return *this;//*this出了函数还在,就可以使用引用返回。}
private:int _year;int _month;int _day;
};
假设我们不使用日期类的print函数,通过<<符号重载,能不能实现日期类的打印?
然后使用:
发现这时无法使用的
原因:
这个内部函数的第一个参数,也就是<<左边的操作数,是this,为日期类
第二个参数为<<右侧的操作数out,为ostream类。
而我们调用的时候,cout << d1,左侧写的是ostream类,右侧写的是日期类,顺序发生了错误。
只要我们将顺序调换就可以正常使用了,但是这不太符合我们平时的使用习惯
要想手动设置两个参数的位置,就不能将其实现为内部的成员函数,而是类外部的函数:
但是,这样,类内部的private参数就不能访问了
这里的解决方法就是实现这个类的各种参数的set和get方法,但是这样有点麻烦
还有一种解决方式,就涉及到了友元。
友元:
友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以要尽可能减少使用。
友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加上friend关键字。
如下:
【BTW】:为了实现能够连续调用,返回类型改成了ostream类型
友元声明可以放在类内的任何地方。
这样就可以实现了<<的重载了。
同理,实现>>的重载,总体如下: