一.流插入,流提取
【流插入的库是在iostream里,流提取的库是在ostream里】
- 可以支持内置类型是因为在库里面实现了
- 可以支持自定义类型,是因为人为进行了函数重载
图示:
此时:cout<<d相当于count.operator(d)
1.为什么流插入<<不能写成成员函数
// 流插入不能写成成员函数? //因为Date对象默认占用第一个参数,就是做了左操作数 如果按照正常使用场景实现出来: count<<d1; 如果写在成员函数里会表现出 count.operator<<(d) 访问不了成员 只有写成 d1 << cout; 才会在成员函数里表现出 d1.operator<<(count) 才能进行传参,访问成员
因此为了使用操作合乎习惯,又要让流插入能够访问成员,只能将流插入重载写在类外(虽然流提取不会出现这种情况,为了统一,一并写在类外)
2.流插入写在类外访问类内成员的方法——友元
但是类内的成员是private(私有的),我们可以通过友元(声明操作符重载函数能进入类内访问的权限)
3.代码展示:
头文件部分:
#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 = 1, int month = 1, int day = 1); void Print() const { cout << _year << "-" << _month << "-" << _day << endl; } Date(const Date& d) // 错误写法:(不加引用)编译报错,会引发无穷递归 { // 拷贝构造 _year = d._year; _month = d._month; _day = d._day; } int GetMonthDay(int year, int month); private: int _year; int _month; int _day; }; //虽然友元已经声明,但那与函数声明不同,仅是表示权限 //这里还是要再次进行函数声明 ostream& operator<<(ostream& out, const Date& d); istream& operator>>(istream& in, Date& d);
.c文件部分:
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 < 13 && day > 0 && day <= d.GetMonthDay(year, month)) { d._year = year; d._month = month; d._day = day; } else { cout << "非法日期" << endl; assert(false); } return in; }
二.基本运算符重载【>,>=,<,<=等】
1.代码展示:
类内声明:
PS:加const,可以让普通变量和const变量都能调用该函数(具体知识点可见YY的C++知识合集博客,关于const的解读)
bool operator<(const Date& x) const; //相当于bool operator<(const Date* const this,const Date& x);,下列声明同理 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;
.c文件实现:
PS:在函数实现过程中可以使用技巧"复用"
(多个函数只需要复用一个定义即可,具体代码)
bool Date::operator==(const Date& x) const { return _year == x._year && _month == x._month && _day == x._day; } 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); } bool Date::operator!=(const Date& x) const { return !(*this == x); }
三.基本运算符重载【+,+=,-,-=】(日期与天数的运算)
1.代码展示:
类内声明:
PS:加const,可以让普通变量和const变量都能调用该函数(具体知识点可见YY的C++知识合集博客,关于const的解读)
PS:const加在后面表示const Date* this ;表明在该成员函数中不能对类的任何成员进行修改,而+=,-=是要实现对类内成员的改变,因此不能加;
Date& operator+=(int day); Date operator+(int day) const; Date& operator-=(int day); Date operator-(int day) const;
.c文件实现:
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; } // d1 + 100 Date Date::operator+(int day) const { //复用+= Date tmp(*this); tmp += day; return tmp; /*tmp._day += day; while (tmp._day > GetMonthDay(tmp._year, tmp._month)) { tmp._day -= GetMonthDay(tmp._year, tmp._month); ++tmp._month; if (tmp._month == 13) { ++tmp._year; tmp._month = 1; } } 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; }