广州百度网站建设公司,广州代做网站,网站换新域名,公司静态网站模板下载目录
一. 对日期类的介绍
二. 实现日期类
1. 运算符重载
2.日期类实现代码 一. 对日期类的介绍
通过对类和对象#xff08;这里链接是类和对象的介绍#xff09;的学习#xff0c;类就是一种模型一样的东西#xff0c;是对象一种抽象的描述。所以实现日期类#xff0… 目录
一. 对日期类的介绍
二. 实现日期类
1. 运算符重载
2.日期类实现代码 一. 对日期类的介绍
通过对类和对象这里链接是类和对象的介绍的学习类就是一种模型一样的东西是对象一种抽象的描述。所以实现日期类就是实现一个日期模型里面有所对应的成员变量属性年/月/日还有一些它的方法成员函数打印该日期、对日期加减等。
二. 实现日期类
在实现日期类之前我们还需要了解一下运算符重载这是为了后续我们对日期的加、减天数以及日期减日期等做准备因为当运算符被用于类类型的对象时需要我们去重载运算符去指定新的含义。C规定类类型对象使用运算符时必须转换成调用对应运算符重载若没有对应的运算符重载则会编译报错。
//内置类型
int i 1;
int j 2;
int sum 0;i i 1;
sum i - j;//自定义类型对象若想用类似上面的就需要在类里面声明定义对应的运算符重载函数
1. 运算符重载 C规定类类型对象使用运算符时必须转换成对应运算符重载若没有对应的运算符重载则会编译报错。 也就是运算符被用于类类型的对象时可以通过运算符重载的形式指定新的含义。
运算符重载是一个函数它的名字是由关键字operator和运算符组成也具有返回类型、参数列表、函数体。
class A
{
public:A(int a 1, int b 1):_a(a),_b(b){}//这里就是赋值运算符重载A operator(const A a){_a a._a;_b a._b;return *this;}
private:int _a;int _b;
};int main()
{A a1;A a2(5, 2);a1 a2;return 0;
}
我们来查看验证是否按照指定新的含义进行
赋值之前 赋值之后 可以看到a1里的成员确实被a2里的成员变量赋值了。
注意
//上述代码中a1 a2;
//其实详细写法是
a1.operator(a2);//但它们俩意义相同都是为了调用赋值运算符重载
一元运算符只有一个参数二元运算符要有两个参数。注意二元运算符的左侧运算对象传给第一个参数右侧运算对象传给第二个参数。
也就是说重载运算符函数的参数个数和该运算符作用的运算对象数量一致的。
上面我们看到A类重载运算符只写了一个函数参数这是因为它是成员函数第一个参数默认传了this指针类和对象有介绍。
注意重载运算符必须至少有一个类类型的形参不能通过运算符重载改变内置类型对象的含义。
若不是成员函数就按照上面规则来
class A
{
public:A(int a 1, int b 1):_a(a),_b(b){}A operator(const A a){_a a._a;_b a._b;return *this;}int _a;int _b;
};//注意operator 必须至少有一个类类型的形参否则会报错,就比如下面注释掉的情况
//int operator(int a,int n)
//{
// return a-n;
//}int operator(const A a, int n)
{return a._a n; //这里成员变量需要放公有否则不能直接访问
}int main()
{A a;int n 10;cout a n endl;return 0;
} 运算符重载以后优先级和结合性与对应的内置类型运算符保持一致的。
不能重载的情况
不能用没有的符号创建新的操作符运算符 //例如
operator //就不能创建 有五个运算符是不能重载的.* :: sizeof . 后四个是经常用到的第一个非常用下面单独拿出来解释
//函数指针较为特别typedef类型需要这样写
typedef void (*PF)(); class A
{
public:void func(){cout A::func() endl;}
};//若typedef成员函数指针类型就加个指定类域即可
typedef void(A::*PF)();// .*运算符就用于以下方式回调函数的场景成员函数回调
int main()
{//成员函数要加才能取到函数指针PF pf A::func; //这里相当于 void(A::*pf)() A::func;A a;(a.*pf)();return 0;
} 深入理解指针
//这里是普通全局函数回调的形式
(*pf)();
所以这个符号的意义是对象调用成员函数指针时成员函数的回调 注意考虑有隐含的this指针不能显示写形参和传实参 重载运算符时前置与后置的运算符重载函数名都是operator无法来区分。 C规定后置重载时增加一个int形参跟前置构成函数重载方便区分。 class Date
{
public://构造函数Date(int year 1900,int month 1,int day1):_year(year),_month(month),_day(day){}//前置Date operator(){cout 这里是前置 endl; //这里演示一下先不实现return *this;}//后置Date operator(int) //这里的加不加形参名都可以必须要有int 只要整型{Date tmp;cout 这里是后置 endl; return tmp;}private:int _year;int _month;int _day;
};int main()
{Date d1;Date d2;d1;d2;d2.operator(10); //这里传不传值都可以因为那个int一般不接收。
} 注意重载的运算符也要与内置类型运算符规则一致前置先再返回后的结果不产生拷贝后置进行之后返回的是前的结果会产生拷贝。所以一般开以选择前置来减少拷贝。 我们实现日期类还想需要可以对这个日期cout和cin来方便输出和输入所以和也是可以重载的但是需要重载成全局函数重载为全局函数把ostream/istream放到第一个形参位置就可以了第二个形参位置当类类型对象。否则会有隐含的this指针导致调用时变成对象cout 不符合使用习惯和可读性想要的是cout对象。
2.日期类实现代码
我们可以声明定义分离来实现分别创建Date.h头文件和Date.cpp用来定义头文件声明的函数。
//Date.h#includeiostream
#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 1900, int month 1, int day 1);//拷贝构造Date(const Date d);void Print()const; //打印日期bool CheckDate() const; //检查日期输入是否正确//频繁调用的建议直接定义类里面默认inline内联int GetMonthDay(int year, int month)const {assert(month 0 month 13);static int monthDay[13] { -1,31,28,31,30,31,30,31,31,30,31,30,31 }; //因为没有0月将0置-1空出来//用static修饰是因为这个数组会频繁调用直接放在静态区if (month 2 ((year % 4 0 year % 100 ! 0) || (year % 400 0))){return 29;}return monthDay[month];}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;//d1 d2Date operator(const Date d);Date operator(int day) const;Date operator(int day);Date operator-(int day) const;Date operator-(int day);// d1;// d1.operator(0);Date operator(int);// d1;// d1.operator();Date operator();// d1--;// d1.operator--(0);Date operator--(int);// --d1;// d1.operator--();Date operator--();// d1 - d2int operator-(const Date d) const;//void operator(ostream out);Date* operator() //取地址运算符重载 //普通对象返回类型Date*{return (Date*)0x2673FF40; //返回假地址}const Date* operator() const //取地址运算符重载 //const对象要调用const成员函数要返回类型const Date*{return (Date*)0x2673FE30; //返回假地址 }
private:int _year;int _month;int _day;
};//重载流插入流提取
// ostream/istream类型对象不能传值只能传引用否则会报错因为c不支持它们的拷贝构造。
//要写成全局函数 否则调用的时候需要这样写d1cout d1cin 用着会比较别扭
//因为如果写成了成员函数第一个参数有隐藏的this指针并且不能修改
//cout是ostream类型的 也可以用void返回类型但不建议
//cin默认关联cout
//在cin进行i/o操作前会刷新cout的缓冲区//流插入
ostream operator(ostream out, const Date d);//流提取
//这里第一个参数不能加const修饰了因为提取的值要放日期类对象里
istream operator(istream in, Date d);
//Date.cpp#include Date.h
bool Date::CheckDate() const//检查日期正确
{if (_month 1 || _month 12|| _day 1 || _day GetMonthDay(_year, _month)){return false;}else{return true;}
}Date::Date(int year, int month, int day) //构造函数全缺省前面声明中已经给了缺省值定义这里就不能再写出来了
{_year year;_month month;_day day;if (!CheckDate()){cout 非法日期:;Print();}cout endl;
}Date::Date(const Date d) //拷贝构造
{_year d._year;_month d._month;_day d._day;
}void Date::Print()const //打印日期
{cout _year / _month / _day endl;
}//d1 d2
Date Date::operator(const Date d)
{if (*this ! d){_year d._year;_month d._month;_day d._day;}return *this;
}Date Date::operator(int day) //加等可以让自己改变
{//先判断day是否是负数 ---- _day(-day)_day-dayif (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(int day) const //只加不能改变自己
//这里不能用传引用返回 因为这里用const修饰只读取不想改变自己引用会把权限放大
{Date tmp *this;tmp day;return tmp;
}//- -同
Date Date::operator-(int day) const
{Date tmp *this;tmp - day;return tmp;
}
Date Date::operator-(int day)
{//先判断day是否是负数 ---_day-(-day)_daydayif (day 0) {return *this (-day);}_day - day;while (_day 0){--_month;if (_month 0){_month 12;--_year;}_day GetMonthDay(_year, _month);}return *this;
}//d1d2
bool Date::operator(const Date d) const //这里传引用 d就是d2的别名 也就是d2的本身
{if (_year d._year){return true;}else if (_year d._year){if (_month d._month){return true;}if (_month d._month){return _day d._day;}}return false;
}//d1d2
//这里就可以复用函数了
bool Date::operator(const Date d) const
{return *this d || *this d;
}
bool Date::operator(const Date d) const
{return !(*this d);
}
bool Date::operator(const Date d) const
{return !(*this d);
}
bool Date::operator(const Date d) const
{return (_year d._year) (_month d._month) (_day d._day);
}
bool Date::operator!(const Date d) const
{return !(*this d);
}// d1; 后置有拷贝
// d1.operator(0);
//用的时候括号里只要是整数都可以
Date Date::operator(int) // 加不加形参名都可以,一般不接收
{Date tmp *this;*this 1;return tmp;
}// d1; //前置无拷贝
// d1.operator();
Date Date::operator()
{*this 1;return *this;
}//-- 同理
// d1--;
// d1.operator--(0);
Date Date::operator--(int)
{Date tmp *this;*this - 1;return tmp;
}// --d1;
// d1.operator--();
Date Date::operator--()
{*this - 1;return *this;
}// d1 - d2
int Date::operator-(const Date d) const
{Date max *this; //假设第一个大Date min d; //第二个小int flag 1; //等于1时表示第一个大第二个小if (*this d){max d;min *this;flag -1; //第二个大第一个小}int n 0;while (min ! max){min;n;}return n * flag;
}//流插入coutd1d2
ostream operator(ostream out, const Date d)
{cout d._year 年 d._month 月 d._day 日 endl;return out;
}//流提取cind1d2
istream operator(istream in, Date d)
{cout 请依次输入年月日:;in d._year d._month d._day;//检查日期是否非法if (!d.CheckDate()){cout 非法日期: d 请重新输入 endl;while (1){cout 请依次输入年月日:;in d._year d._month d._day;if (!d.CheckDate()){cout 输入日期非法:;d.Print();cout 请重新输入!!! endl;}else{break;}}}return in;
} 有些注意事项在上面代码的实现注释中有一些解释。 制作不易,若有不足之处或出问题的地方请各位大佬批评指正 感谢大家的阅读支持