寮步镇做网站,汕头网站制作推荐,各种手艺培训班,网站图片被盗连怎么办啊前言 在学习了类和对象的六大成员函数后#xff0c;为了巩固我们学习的知识可以手写一个日期类来帮助我们理解类和对象#xff0c;加深对于其的了解。
默认函数 构造函数 既然是写类和对象#xff0c;我们首先就要定义一个类#xff0c;然后根据实际需要来加入类的数据与函… 前言 在学习了类和对象的六大成员函数后为了巩固我们学习的知识可以手写一个日期类来帮助我们理解类和对象加深对于其的了解。
默认函数 构造函数 既然是写类和对象我们首先就要定义一个类然后根据实际需要来加入类的数据与函数。作为一个日期类肯定要有时间了我们采用公元纪年法存储三个变量年 月 日如下。
class Date
{private:int _year;int _month;int _day;
}; 注意这里将三个成员变量定义为private:是为了防止用户在外面修改提高安全性。其次这里在每个成员变量前面加了个下划线。 _year这里是为了防止后面与函数的参数重名。当然重名也有其他解决方法例如用this.year也可以。具体选那种看读者更适合那种编码风格。 写完上面的变量后我们第一个想到要写的函数必定是构造函数了。如下函数
Date(int year1900, int month1, int day1)
{_year year;_month month;_day day;
} 注意我们这里写成了全缺省这样做的好处是不用写无参的构造函数给每个日期对象都有默认值。
拷贝构造函数 其次我们要写的就是拷贝构造函数。注意这里的形参加了个const这里加了const一是为了方防止修改形参d二是为了通用性。如下例子 Date(const Date d){_year d._year;_month d._month;_day d._day;} 假如我们没有加const有下述程序。这段代码会报错为什么呢d1的类型为const Date,而拷贝构造函数参数类型为Date d如果传参成功是不是就可以在构造函数的内部修改原本为const类型的变量违背了基本的定义语法。但用一个const Date类型拷贝初始化是我们需要的场景为了让其正常运行就需要在拷贝构造函数加const。
int main()
{const Date d1(2024, 4, 16);Date d2(d1);return 0;
} 有const变量自然也有普通的变量了。我们就可以写个普通变量的拷贝构造函数。
Date(Date d)
{_year d._year;_month d._month;_day d._day;
} 其实在很多地方会将上面两个构造函数简化为一个即保留含const的
Date(const Date d)
{_year d._year;_month d._month;_day d._day;
}那自然有人问普通变量的拷贝怎么办呢在这里就不得不提C对于变量类型的处理了。我们首先看段熟悉的代码。
int a0;a1.12; 这段代码会报错么为什么大家可以在程序中运行下结果是不会报错的有的编译器可能会有警告。大家知道整型与浮点型在内存中的存储方式是不一样的即使是对浮点型内存的截断读取a也不可能为1. 但a的结果却是一这是因为编译器帮我们做了类型转化称之为隐式转换。如下图。 同理当我们将Date变量赋给const Date d编译器也会额外开辟空间付给形参d。 或许有读者又有疑问Date变量赋给const Date d可以为什么const Date变量赋给Date d不可以因为前者是将内存的权限放小而后者是将对内存的权限放大。在C中将权限放小可以但把权限放大就有可能产生难以预料的后果。 接下来我们来实现与拷贝构造函数功能十分像的赋值重载函数。
赋值重载函数 代码如下 Date operator(const Date d){if (d ! this){_year d._year;_month d._month;_day d._day;}return *this;} 这里我们任然将参数的类型加上const省去对于普通变量与const变量的分类了当然对于普通变量会隐式转换会减少些效率。 注意这里将d的地址与this比较这是为了防止自己和自己赋值的情况如 aa这样没有任何的意义。
析构函数 在这个对象中我们没有开辟内存没有在堆区申请空间写不写析构函数都可以。
~Date()
{} 成员函数
重载 我们为了后续的方便首先要实现的便是cout输出Date类型对于内置类型cout可以直接的输出但是对于自定义类型要我们使用操作符重载. 按照习惯我们极大概率会将写在类里面。写出如下的代码
ostream operator(ostream out)
{out _year - _month - _day endl;return out;
}其中的ostream参数是输出时要用到的一种类型返回值为ostream是为了连续输出的原因。这个看起来没有什么错误但运行的时候就会报错 我们明明重载了操作符为什么却提示我们没有匹配类型呢这就不得不提到this了在使用cout d1操作符重载的时候我们从左向右显然要传递两个参数ostream和Date在类中的成员函数默认第一个参数传递Date即形参this指针第二个实参初始化函数的形参。 关于this指针详情可以看【C 类和对象 上 - CSDN App】http://t.csdnimg.cn/Wx5iO。在这里就不叙述了。 于是上面的代码也不是不可以用可以采用如下的方法使用 但这种方法显然是不符合我们日常认知的。 为了解决这种问题我们把操作符改为全局函数。就可以解决顺序的问题了。如下代码
ostream operator(ostream out, const Date d)
{out d._year 年 d._month 月 d._day 日 endl;return out;
} 但此时又有一个新的问题这个重载函数不可以访问Date对象中私有的成员变量这就体现了我们类的安全性高为了解决我们需要把这个操作符重载函数声明为友元函数就可以了。
class Date
{
public:Date(int year1900, int month1, int day1){_year year;_month month;_day day;}Date(const Date d){_year d._year;_month d._month;_day d._day;}Date operator(const Date d){if (d ! this){_year d._year;_month d._month;_day d._day;}return *this;}friend ostream operator(ostream out, const Date d);private:int _year;int _month;int _day;
};这样我们就可以正常输出了。
重载 有了输出当然要有其对应的输入最好。和输出重载一样将操作符重载为全局函数并且在类中声明为友元函数。
istream operator(istream in, Date d)
{in d._year d._month d._day;return in;
} 如下图刚开始输出1900时我们写的全缺省参数的作用而后输出的就是我们输入的2024 5 13. 光有输入输出函数显然是不可以的我们也要有对应的函数。 大小比较 对于一个日期比较大小是符合实际需求的我们可以写个cmp成员但更好的使用操作符重载 这个我们最熟悉又可以减小记忆的负担。
比较 我们有两种方法比较两个日期的大小。
方法一 不断地寻找true条件最后剩下的就是false。注意年数相等的时候要判断月份
bool Date::operator(Date d)
{if (_year d._year){return true;}else if (_year d._year){if (_month d._month){return true;}else if (_month d._month){if (_day d._day){return true;}}}return false;
}方法二 将日期的比较转换为数的比较。月份最多有12月天最多有31天我们就可以将年扩大10000倍月扩大100倍将2024年5月13日与2023年4月20日比较转换为2024513与2023420比较。我们知道数的比较大小是从高位往下开始比较的。这与我们比较日期的顺序不谋而合就可以如下的简化代码。
bool Date::operator(Date d)
{return _day _month * 100 _year * 10000 d._day d._month * 100 d._year * 10000;
}
同理小于等于。大于等于小于都可以如上比较。
bool Date::operator(Date d)
{return _day _month * 100 _year * 10000 d._day d._month * 100 d._year * 10000;
}
bool Date::operator(Date d)
{return _day _month * 100 _year * 10000 d._day d._month * 100 d._year * 10000;
}
bool Date::operator(Date d)
{return _day _month * 100 _year * 10000 d._day d._month * 100 d._year * 10000;
}
bool Date::operator!(Date d)
{return _day _month * 100 _year * 10000 !d._day d._month * 100 d._year * 10000;
} 判断两个日期是否相等的代码也十分简单如下。
相等判断
bool Date::operator(Date d)
{return _year d._year _month d._month _day d._day;
} 到此我们的比较函数就写完了。但光有比较还不可以我们可能想要知道50天后是哪一天50天前是那一天两个日期相差多少天。
加减操作 在后续的操作中我们不可避免的要访问某年某月有多少天我们便可以将他封装为成员函数便于我们查找天数。
获取天数 我们可以将每个月的天数写在一个数组中然后哪一个月就读取哪一个数字但其中2月十分特殊要分为润年的问题要单独判断下。
int Date::GetMonthDay(Date d)
{static int arr[13] { 0,31,28,31,30,31,30,31,31,30,31,30,31 };if (d._month 2 ((d._year % 400 0) || (d._year % 4 0 d._year % 100 ! 0))){return 29;}return arr[d._month];
} 这里将数组加上static 是为了避免重复创建提高效率。然后就是判断是不是闰年的二月。
重载 我们可以将一个日期类加上n天返回加n天后的日期。
Date Date::operator(int t)
{_day t;while (_day GetMonthDay(*this)){_day - GetMonthDay(*this);_month;if (_month 13){_month 1;_year;}}return *this;
} 我们整体的循环是在找当前月合理的天数如果不合理就月份加一天数减去当前月继续判断直到结束。 测试结果正确。 大家写的时候可以用日期计算器 - 天数计算器 | 在线日期计算工具 (sojson.com)这个网站检测。
重载 我们之前已经写完了先在写的思路是不是与类似我们可以仿照写出重载但是我们还有更加简单的方法复用
Date Date::operator(int t)
{Date t1 *this;t1 t;return t1;
} 这样复用代码就大大简化了我们写代码的复杂度。其实上面的判断也可以复用代码读者可以自行尝试。
-重载 一个日期减去一个天数与一个日前加上一个天数十分像。天数小于肯定是不合理的日期就加上当前月数。不断的循环判断直到合理数据。
Date Date::operator-(int t)
{_day - t;while ( _day1 ){_month--;if (_month 0){_month 12;_year--;}_day GetMonthDay(*this);}return *this;
} -重载 与之前一样我们复用-的函数。
Date Date::operator-(int t)
{Date tmp *this;tmp - t;return tmp;
} 我们如果对负数-负数会怎么样显然程序会崩溃但这又可能是我们使用者的操作于是便可以在不同的重载函数互相调用。 如下代码
Date Date::operator-(int t)
{if (t 0)return *this (-t);Date tmp *this;tmp - t;return tmp;
} 日期相减
方法一 我们当然会求两个日期之间的差数。便可以重载-。我们可以对小的天数一直加一直到二者相等。如下
int Date::operator-(Date d)
{assert(*this d);Date t1 *this;Date t2 d;int t 0;//一直加while (t1 ! t2){t2 1;t;}return t;
} 我们有时也会写的前一个日期小导致相差负数为了达到这种效果也可以对上述代码稍加修改。
int Date::operator-(Date d)
{if (*this d)return d - *this;Date t1 *this;Date t2 d;int t 0;//一直加while (t1 ! t2){t2 1;t;}return t;
}
方法二 上述的代码十分简单效率有些不理想我们可以换种方法。 首先我们先判断二者是否相同不相同在判断t2的天数是否小于t1,小于说明可能只是天数不同将天数加到t1的天数然后判断是否相等。如果t1的天数等于t2的天数说明月份不同将t2的月份一次往上加一判断二者是否相等。
int Date::operator-(Date d)
{if (*this d)return d - *this;Date t1 *this;Date t2 d;int t 0;//一直加while (t1 ! t2){int c GetMonthDay(t2);if (t2._day t1._day t1._day c){t t1._day - t2._day;t2._day t1._day;}else {t2._month;if (t2._month 13){t2._year;t2._month 1;}t c - t2._day 1;t2._day 1;}}return t;
} 这种方法的效率比第一种高了许多。
结语 到这里本篇文章就结束了。喜欢的点点关注
全部代码如下。
#includeiostream
#includeassert.h
using namespace std;class Date
{
public:Date(int year1900, int month1, int day1){_year year;_month month;_day day;}Date(const Date d){_year d._year;_month d._month;_day d._day;}Date operator(const Date d){if (d ! this){_year d._year;_month d._month;_day d._day;}return *this;}//友元函数声明friend ostream operator(ostream out, const Date d);friend istream operator(istream in, Date d);//比较函数bool operator(Date d);bool operator(Date d);bool operator(Date d);bool operator(Date d);bool operator(Date d);bool operator!(Date d);//加减操作函数Date operator(int t);Date operator(int t);Date operator-(int t);Date operator-(int t);int operator-(Date d);int GetMonthDay(Date d);private:int _year;int _month;int _day;
};//bool Date::operator(Date d)
//{
// if (_year d._year)
// {
// return true;
// }
// else if (_year d._year)
// {
// if (_month d._month)
// {
// return true;
// }
// else if (_month d._month)
// {
// if (_day d._day)
// {
// return true;
// }
// }
// }
// return false;
//}
//bool Date::operator(Date d)
//{
// return !(*this d);
//}
//bool Date::operator(Date d)
//{
// return *this d || d *this;
//}
//bool Date::operator(Date d)
//{
// return *this d || d *this;
//}
//bool Date::operator!(Date d)
//{
// return !(d *this);
//}bool Date::operator(Date d)
{return _day _month * 100 _year * 10000 d._day d._month * 100 d._year * 10000;
}bool Date::operator(Date d)
{return _day _month * 100 _year * 10000 d._day d._month * 100 d._year * 10000;
}
bool Date::operator(Date d)
{return _day _month * 100 _year * 10000 d._day d._month * 100 d._year * 10000;
}
bool Date::operator(Date d)
{return _day _month * 100 _year * 10000 d._day d._month * 100 d._year * 10000;
}
bool Date::operator!(Date d)
{return _day _month * 100 _year * 10000 !d._day d._month * 100 d._year * 10000;
}
bool Date::operator(Date d)
{return _year d._year _month d._month _day d._day;
}int Date::GetMonthDay(Date d)
{static int arr[13] { 0,31,28,31,30,31,30,31,31,30,31,30,31 };if (d._month 2 ((d._year % 400 0) || (d._year % 4 0 d._year % 100 ! 0))){return 29;}return arr[d._month];
}Date Date::operator(int t)
{if (t 0)return *this - (-t);_day t;while (_day GetMonthDay(*this)){_day - GetMonthDay(*this);_month;if (_month 13){_month 1;_year;}}return *this;
}Date Date::operator(int t)
{Date t1 *this;t1 t;return t1;
}Date Date::operator-(int t)
{if (t 0)return *this (-t);_day - t;while ( _day1 ){_month--;if (_month 0){_month 12;_year--;}_day GetMonthDay(*this);}return *this;
}Date Date::operator-(int t)
{if (t 0)return *this (-t);Date tmp *this;tmp - t;return tmp;
}int Date::operator-(Date d)
{if (*this d)return d - *this;Date t1 *this;Date t2 d;int t 0;//一直加while (t1 ! t2){int c GetMonthDay(t2);if (t2._day t1._day t1._day c){t t1._day - t2._day;t2._day t1._day;}else {t2._month;if (t2._month 13){t2._year;t2._month 1;}t c - t2._day 1;t2._day 1;}}return t;
}ostream operator(ostream out, const Date d)
{out d._year 年 d._month 月 d._day 日 endl;return out;
}istream operator(istream in, Date d)
{in d._year d._month d._day;return in;
}