专业做互联网招聘的网站,文学网站怎样建设,深圳市网站设计公,免费做网站的好不好作者:chlorine 专栏:c专栏 赋值运算符重载()()():实现完整的日期类(上) 我走的很慢#xff0c;但我从不后退。 【学习目标】 日期(- - --)天数重载运算符 日期-日期 返回天数 对日期类函数进行优化(不符合常理的日期#xff0c;负数#xff0c;const成员)c中重载输入cin和输… 作者:chlorine 专栏:c专栏 赋值运算符重载()()():实现完整的日期类(上) 我走的很慢但我从不后退。 【学习目标】 日期(- - --)天数重载运算符 日期-日期 返回天数 对日期类函数进行优化(不符合常理的日期负数const成员)c中重载输入cin和输出cout运算符const成员 首先我要对上面一篇类和对象(上)进行补充上一篇主要内容 赋值运算符重载 ! 重载运算符前置 后置’ 重载运算符
相信大家对于operator的运用以及重载运算符有了一定的了解。本次博客我会继续深化赋值运算符重载的内容并对各函数进行优化处理。 目录
— -重载运算符
前置--后置-- 日期-日期天数
(-)负数 (优化)
C中重载输入cin和输出cout运算符
重载输入cin运算符
重载输入cout运算符
不符合常理的日期(优化)
const成员(优化)
const对于和
const对于d1d2?和d1d2
️完整代码
Date.h
Date.cpp
test.cpp — -重载运算符 我们不只局限于对未来的计算虽然以前的日子已经一去不复返。如果我们想知道100天是哪一天该如何操作呢上面的图片今天是2023年11月18日一百天前是2023年8月10日这是该如何计算呢
11月已经被-100了这里要上的是10月份的天数。 计算过程如图所示。我们可以根据上面思路进行写代码。
主要思路先将日-100然后如果是负数就进入循环 月份-1就可以得到在此基础上的上一个月的天数然后我们还要考虑一个情况就是如果月份0我们就要追溯到上一年的12月开始。代码如下 Date Date::operator-(int day)
{_day-day;while(_day0){--_month;if(_month0){_month12;--_year;} _dayGetMonthDay(_year,_month);}return *this;
} 那么-重载运算符和重载运算符一个道理不能改变原来的值就创建一个临时变量tmp保留d1原来的值然后返回tmp.
依旧使用-复用-的方法. Date Date::operator-(int day)
{Date tmp(*this);tmp -day;return tmp;
} 前置--后置--
前置--后置--和前置后置的用法是一样的
前置--返回的减之后的值。后置--返回的减之前的值需要用拷贝构造创建 一个临时变量tmp来保存原来的值。并且后置--重载时多增加一个int类型的参数但调用函数时该参数不用传递编译器自动传递 。 //前置--返回的是减之后的值
Date Date::operator--()
{*this - 1;return *this;
}//后置--返回的是减之前的值
Date Date::operator--(int)
{Date tmp *this;*this - 1;return tmp;
} 日期-日期天数
我想计算一下自己的生日和今天相差多少天我该如何用代码实现呢 第一种思路
我们可以与小的日期和大的日期的年份设置成一样的然后就可以利用 《月和日对齐利用年判断润平年闰年一年多少天平年一年的多少天相加然后算出了2003-10-29~~~2023-10-29相差多少天然后 《年对齐利用获得每个月的天数进行相加》
思路的俩个步骤比较于直接减方便多了。
第二种思路
d1-d2 我们先假设d1是小min日期d2是大max日期如果我的猜测不对就将min赋值给d2,max赋值给d1。我们要用flag1或-1来记录如果(小-大就得乘以-1)(大-小就得乘以1小的数如果一直是可以与大的数持平的我们就进行一个循环直到minmax的时候结束过程中min一直用n来记下min一直的次数n的值就是天数。
代码如下 int Date::operator-(const Date d)
{Date max *this;Date min d;int flag 1;if (*thisd){min *this;max d;flag -1;}int n 0;while (min ! max){min;n;}return n*flag;
} 计算机的效率是可以完成循环多次的。 (-)负数 (优化)
图中不管是还是-都是成立的对于day是正是负都是可以计算的。 day -100; 大家有没有想过如果day是负数呢上面的代码运行的结果是什么呢 这时候我们该如何优化呢 d1 -day 是不是相当于 d1-day? 那么就可以复用-重载运算符。
这样对嘛d1 -100,本来是看以前的日子的怎么算到2024了这里我们就要考虑到数学的知识了。 *this是d1 d1-day ,day是-100那么负负得正 就成了d1day,所以我们需要在day前面加个负号即d1- -day。 -day100,所以 d1-100 与 d1-100 等式成立。 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,看100天后的日期那么就相当于负负得正d1100,那么用到-函数里就是 d1-day. 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;
} C中重载输入cin和输出cout运算符
c系统实现了一个庞大的类的库如下图所示。其中ios为基类其他类都直接或间接派生自ios类.
cin和cout可以直接输入和输出内置类型如int、double等和部分标准自定义类型如string等原因是标准库已经将所有这些类型的输入和输出重载了直接使用即可。
对于我们自定义的类型如果想直接使用cin、cout来输入输出需要自己重载和否则不能直接使用。
在C中标准库本身已经对左移运算符和右移运算符分别进行了重载使其能够用于不同数据的输入输出但是输入输出的对象只能是 C内置的数据类型例如 bool、int、double 等和标准库所包含的类类型例如 string、complex、ofstream、ifstream 等。如果自己定义了一种新的数据类型需要用输入输出运算符去处理那么就必须对它们进行重载。本节以Date类为例来演示输入输出运算符的重载。 cout _year - _month - _day endl;//输出形式
cin_year_month_day; //输入形式cout是ostream类的对象cin是istream类的对象要想达到这个目标就必须以全局函数友元函数的形式重载和否则就要修改标准库中的类这显然不是我们所期望的。
重载输入cin运算符
以全局函数的形式重载
//cin重载
istream operator(istream _in, Date d)
{_in d._year d._month d._day;return _in;
} 注意运算符重载函数中用到了Date类的private 成员变量必须在Date类中将该函数声明为友元函数如下例所示:
friend istream operator (istream _in,Date d); 重载输入cout运算符
同样地也可以模仿上面的形式对输入运算符进行重载让它能够输出请看下面的代码 //cout重载
ostream operator(ostream _out, const Date d)
{_out d._year - d._month - d._day endl;return _out;
} ostream表示输出流cout是ostream类的对象。由于采用了引用的方式进行参数传递并且也返回了对象的引用所以重载后的运算符可以实现连续输出。
为了能够直接访问Date类的private成员变量同样需要将该函数声明为complex类的友元函数friend ostream operator (ostream out, complex A); 友元函数的声明
我们有没有观察到
为什么输入重载里面的参数不加而输出相反。
——输入年月日如果输入流不能修改那么就没办法进行输入了输出在输入之后了它保留着日期是不能被修改的。 在这之前加coonst也是编译不过的因为流入和流出的过程取它们其中的值也是需要改变它的状态值所以输出输入都是不能加const的。 提取完了之后要改变其中内部的状态值的。
输入输出重载运算符代码如下
//cin重载
istream operator(istream _in, Date d)
{_in d._year d._month d._day;return _in;
}//cout重载
ostream operator(ostream _out, const Date d)
{_out d._year - d._month - d._day endl;return _out;
} 我们继续优化吧~ 不符合常理的日期(优化) 这个日期符合常理嘛显然是不符合的。所有的对象是构造出来的所以我们再构造的时候加一些检查~ 第一种直接打印出“非法日期”第二种直接断言报错暴力法 既然输出流对于不合理的日期进行了检查那么输入呢 输入非法日期之后是可以直接通过的那我们就得给流输入进行检查。 //cin重载
istream operator(istream _in, Date d)
{//第一种写法_in d._year d._month d._day;if (d._month 0 d._month 13 d._day0 d._day d.GetMonthDay(d._year, d._month)){}else{//cout 非法日期 endl;assert(false);}return _in;//第二种写法int year, month, day;_in year month day;if (month 0 month 13 day0 day d.GetMonthDay(year, month)){d._year year;d._month month;d._day day;}else{//cout 非法日期 endl;assert(false);}
}
一共俩种写法第二种更灵活。 const成员(优化) 将 const 修饰的 “ 成员函数 ” 称之为 const 成员函数 const 修饰类成员函数实际修饰该成员函数 隐含的 this 指针 表明在该成员函数中 不能对类的任何成员进行修改。 如何让权限平移或者缩小呢我们只需要给Date*this改成const Date*this就可以了。 我们不能动this的类型因为它是隐含的是无法动的那么如何将类型改成const使权限不放大呢所以祖师爷就直接再函数后面加个const就可以了。
这里加个const 修饰的是*this。const Date* this我们之前就复习了const这里const修饰的类型是Date修饰的内容是*this。
重点成员函数后面加const以后普通和const对象都可以调用权限的平移和权限的缩小。 const对于和 那我们所写的所有成员函数都能加个const嘛 ——当然不是要修改的对象成员变量函数不能加。 比如成员函数后面加个const。 _day》this-day,const修饰的是this指向的内容指向的内容都不能修改如何呢——肯定不行。那么呢 不会改变我自己我们上面说了成员函数后面加const以后普通和const对象都可以调用权限的平移和权限的缩小。只要不改变成员变量都可以加 所以我们看看还有什么可以加const const对于d1d2和d1d2? 为什么d1d2可以d2d1不可以呢 这里就考虑到了权限的放大缩小平移问题了d2是const显然传过去就是权限的放大当然是不可以的。所以最好的方式就是给这些成员函数都加const。 结论只要成员函数内部不修改成员变量就应该加const这样const对象和普通对象都可以调用。 这些成员函数都可以后面加const,因为按上面的结论就是不修改内部成员变量。 ️完整代码
Date.h
#pragma once
#includeiostream
#includeassert.h
using namespace std;
class Date
{//友元函数的声明friend ostream operator(ostream _out, const Date d);friend istream operator(istream _in, Date d);
public:int GetMonthDay(int year, int month){int array[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;}else{return array[month];}}void print() const{cout _year - _month - _day endl;}Date(int year 2003, int month 10, int day 5);Date operator(const Date d);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;//日期天数Date operator(int day) const;Date operator(int day);// 日期-天数Date operator-(int day)const;//自己不能改变。但是返回之后的结果Date operator-(int day);//前置Dateoperator();//后置Date operator(int);//前置--Date operator--();//后置--Date operator--(int);//日期-日期int operator-(const Date d)const;private:int _year;int _month;int _day;
};Date.cpp
#includeiostream
using namespace std;#includeDate.hDate::Date(int year, int month, int day)
{if (month0month13day0dayGetMonthDay(year,month)){_year year;_month month;_day day;}else{//cout 非法日期 endl;assert(false);}
}//赋值运算符重载
Date Date::operator(const Date d)
{_year d._year;_month d._month;_day d._day;return (*this);
}bool Date::operator(const Date d)const
{return _year d._year _month d._month _day d._day;
}bool Date::operator(const Date d)const
{if (_year d._year){return true;}else if (_year d._year _month d._month){return true;}else if (_year d._year _month d._month _day d._day){return true;}else{return false;}
}bool Date::operator(const Date d)const
{return *this d || *this d;
}bool Date::operator(const Date d)const
{return !(*thisd);
}bool Date::operator(const Date d)const
{return !(*this d);
}bool Date::operator!(const Date d)const
{return !(*this d);
}复用
//Date Date::operator(int day)
//{
// *this *this day;
// return *this;
//}
//
//Date Date::operator(int day)
//{
// Date tmp(*this);
// 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)const
{Date tmp(*this);tmp day;return tmp;
}//d1100
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;
}//前置返回的是加之后的值
Date Date::operator()
{*this 1;return *this;
}//后置返回的是加之前的值
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;
}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;
}int Date::operator-(const Date d)const
{Date max *this;Date min d;int flag 1;if (*thisd){min *this;max d;flag -1;}int n 0;while (min ! max){min;n;}return n*flag;
}//cin重载
istream operator(istream _in, Date d)
{//第一种写法_in d._year d._month d._day;if (d._month 0 d._month 13 d._day0 d._day d.GetMonthDay(d._year, d._month)){}else{//cout 非法日期 endl;assert(false);}return _in;//第二种写法int year, month, day;_in year month day;if (month 0 month 13 day0 day d.GetMonthDay(year, month)){d._year year;d._month month;d._day day;}else{//cout 非法日期 endl;assert(false);}
}//cout重载
ostream operator(ostream _out, const Date d)
{_out d._year - d._month - d._day endl;return _out;
}
test.cpp
#includeDate.hvoid TestDate1()
{Date d1(2003, 10, 5);Date d2(2003, 11, 5);int retd1 d2;int ret2 d1 d2;int ret3 d1 d2;int ret4 d1 d2;cout ret3 endl;
}void TestDate2()
{Date d1(2003, 11, 14);Date d2d1 100;//运用拷贝构造创建一个临时变量tmp将*this的值给tmp,*this的值不改变tmp值改变//从而导致了d1dayd1不变tmp改变。返回d1原来的值。//d1 100;//d1 100;d2.print();/*d1;d1.print();d1;d1.print();*/
}void TestDate3()
{Date d1(2023, 11, 17);Date d2d1 -100;d2.print();
}void TestDate4()
{Date d1(2023, 11, 17);//d1--;//后置--返回的是之前的值、--d1;//前置--返回的是之后的值d1.print();
}void TestDate5()
{Date d1(2023, 11, 17);Date d2(2003, 10, 29);cout d1-d2 endl;cout d2 - d1 endl;
}void TestDate6()
{Date d1(2023, 11, 17);d1.print();/*d1 -100;d1.print();*/d1 - -100;d1.print();
}void TestDate7()
{//Date d1(2023, 11, 17);//d1 100;流插入//cout d1;//operator(cout, d1);Date d1(2023, 11, 17);Date d2(2003, 10, 29);cin d1 d2;cout d1 d2;/*Date d4(2023, 13, 1);cout d4;*/}void TestDate8()
{Date d4(2023,13,1);cind4;cout d4;
}void TestDate9()
{Date d1(2023, 11, 17);const Date d2(2023, 11, 17);d1 d2;d2 d1;//d1 100;//d1普通对象//d2 100;//const对象
}int main()
{//TestDate1();//TestDate2();//TestDate3();//TestDate4();//TestDate5();//TestDate6();//TestDate7();//TestDate8();TestDate9();return 0;
}我走的很慢但我从不后退。