定制化网站开发,wordpress search,贵港做网站化司,免费个人网站2018目录
1、前言
2、全缺省的构造函数
3、打印接口
4、拷贝构造
5、赋值运算符重载#xff08;operator#xff09;
5.1赋值重载是默认成员函数#xff0c;重载格式#xff1a;
5.2 赋值重载不能为全局函数
5.3 编译器默认生成
6、析构函数
7、operator
8、ope…目录
1、前言
2、全缺省的构造函数
3、打印接口
4、拷贝构造
5、赋值运算符重载operator
5.1赋值重载是默认成员函数重载格式
5.2 赋值重载不能为全局函数
5.3 编译器默认生成
6、析构函数
7、operator
8、operator
9、operator
10、operator
11、operator
12、operator!
13、operator 日期天数
14、operator 日期天数
15、operator- 日期-天数
16、operator- 日期-天数
17、前置后置前置--后置--
18、日期 - 日期返回天数
19、const成员 1、前言
本篇文章我们将主要实现以下的这些接口
#include iostream
using namespace std;class Date
{
public:// 获取某年某月的天数int GetMonthDay(int year, int month) const;// 全缺省的构造函数Date(int year 1900, int month 1, int day 1);//打印接口void Print() const;// 拷贝构造函数// d2(d1)Date(const Date d);// 赋值运算符重载// d2 d3 - d2.operator(d2, d3)Date operator(const Date d);// 析构函数~Date();//总结一下只读函数可以加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;// !运算符重载bool operator!(const Date d) const;// 日期天数Date operator(int day);// 日期天数Date operator(int day) const;// 日期-天数Date operator-(int day) const;// 日期-天数Date operator-(int day);// 函数重载// 运算符重载// 前置Date operator(); //d1 - d1.operator()// 加一个int参数进行占位跟前置构成函数重载进行区分// 后置Date operator(int); //d1 - d1.operator(0)// 后置--Date operator--(int);// 前置--Date operator--();// 日期-日期 返回天数int operator-(const Date d) const;private:int _year;int _month;int _day;};
本次的项目我们以多文件来写包含以下三个文件 接下来我们就对以上的接口一一进行实现
2、全缺省的构造函数
对于全缺省的构造函数正常写的时候存在一个不足万一传参传的月份与天是不存在的虽然对实例化的对象初始化了但是是违法的因此我们需要判断一下这里就需要我们对月份的天数写一个函数构造的时候先对比一下。
我们这里先实现GetMonthDay接口
// 获取某年某月的天数
int Date::GetMonthDay(int year, int month) const
{static int monthDay[13] { 0,31,28,31,30,31,30,31,31,30,31,30,31 };if(2 month ((year % 4 0 year % 100 ! 0) || (year % 400 0))){return 29;}return monthDay[month];
}
// 全缺省的构造函数
Date::Date(int year, int month, int day)
{if (month 1 || month 12|| day 1 || day GetMonthDay(year, month))// 判断日期是否合法{cout 非法日期 endl;exit(-1);}else{_year year;_month month;_day day;}
}
对于GetMonthDay接口我们写了一个数组存每个月有多少天默认二月是28天在下面我们会判断一下如果是找二月的天数对年进行判断看看是否为闰年为闰年的时候直接返回29其他的就直接返回月份对应的天数。我们对数组使用static修饰因为后面会不断的调用此函数因此我们将其放到静态区只开辟一次节省了时间一次的时间不多但是如果是大量的调用会极大的提升效率。
这里我们会有人问为什么在GetMonthDay接口后面加一个const这里我们来说明一下 3、打印接口
打印接口没什么讲的我们直接一把梭哈
//打印接口
void Date::Print() const
{cout _year 年 _month 月 _day 日 endl;
}打印接口对this使用const修饰是因为有可能我们传过来的对象是const修饰的如果Print接口不加const就涉及权限放大的问题导致出错。改为const后就不存在权限问题了。
4、拷贝构造
对于拷贝如果还有不清楚的可以点击后面的链接里面有对拷贝构造详细讲解哦点这里哦
// 拷贝构造函数
Date::Date(const Date d)
{_year d._year;_month d._month;_day d._day;
}
5、赋值运算符重载operator
5.1赋值重载是默认成员函数重载格式 参数类型const T传引用可以提高传参效率返回值类型T返回引用可以提高返回的效率有返回值目的是为了支持连续赋值检测是否自己给自己赋值返回*this要复合连续赋值的含义 我们按重载格式来写一下
// 赋值运算符重载
// d2 d3 - d2.operator(d2, d3)
Date Date::operator(const Date d)
{if (this ! d)// 存在this就是d的情况{_year d._year;_month d._month;_day d._day;}return *this;
}
5.2 赋值重载不能为全局函数 原因赋值运算符如果不显式实现编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载就和编译器在类中生成的默认赋值运算符重载冲突了故赋值运算符重载只能是类的成员函数。 我们自己写一下试试 我这里使用的vs2019编译器编译器会提示编译期间直接报错了因此赋值运算符重载是不可以为全局函数的。
5.3 编译器默认生成 当我们不写的时候编译器会自动生成一个复制重载函数但是默认生成的函数对内置类型是直接赋值的对自定义类型的成员变量需要调用对应的类赋值重载函数来完成赋值。 因此如果成员变量里存在自定义类型类类型自定义类型的赋值重载函数必须是正确的这样才是对的。
如两个栈实现一个队列队列的赋值重载函数可以默认生成但是栈的必须自己写因为栈存在申请资源如果直接拷贝两个栈使用的是同一块资源这样的话一个是出栈的栈一个是进栈的栈不管进出其实是对同一个栈进行操作这就是错误的。 注意如果类中未涉及到资源管理赋值运算符是否实现都可以一旦涉及到资源管理则必须要实现。
赋值与拷贝的区别拷贝是一个已经存在的对象去初始化另一个要创建的对象
赋值是两个已经存在的对象进行拷贝。
6、析构函数
对于析构函数如果还有不清楚的可以点击后面的链接里面有对析构函数详细讲解哦点这里哦
// 析构函数
Date::~Date()
{_year 0;_month 0;_day 0;
}
7、operator
对 日期日期 的判断中
1、当年小于后就不用再比了直接返回false
2、当年相同比较月月小于后直接返回false
3、当年月都相同日小于后返回false
4、当以上判断都不正确说明前面的日期 大于 后面的日期返回true
// 运算符重载
bool Date::operator(const Date d) const
{if (_year d._year)return false;else if (_year d._year _month d._month)return false;else if (_year d._year _month d._month _day d._day)return false;elsereturn true;
}
8、operator
对 日期日期 的判断很简单年月日分别都相等就是正确的我们看看代码实现
// 运算符重载
bool Date::operator(const Date d) const
{if (_year d._year _month d._month _day d._day)return true;elsereturn false;
}
上面的代码还可以再精简一下
bool Date::operator(const Date d) const
{return _year d._year _month d._month _day d._day;
}
9、operator
对于 来说我们其实可以复用上面的 与 不用再去写一套逻辑来判断 的逻辑就是大于或者等于。
我们来看看实现代码
// 运算符重载
bool Date::operator(const Date d) const
{return (*this d) || (*this d);
}
10、operator 与 是相反的逻辑因此我们对 取反就可以实现。
// 运算符重载
bool Date::operator(const Date d) const
{return !(*this d);
}
11、operator 与 是相反的逻辑因此我们对 取反就可以实现。
// 运算符重载
bool Date::operator(const Date d) const
{return !(*this d);
}
12、operator!
! 与 是相反的逻辑因此我们对 取反就可以实现。
// !运算符重载
bool Date::operator!(const Date d) const
{return !(*this d);
}
13、operator 日期天数
是在原基础上进行修改因此隐含的this不能用const修饰因为在原基础上修改所以出了函数体对象还在我们使用引用返回这样可以减少拷贝。
我们画图对 天数分析 代码实现
// 日期天数
Date Date::operator(int day)
{if (day 0){return *this - (-day);}_day day;while (_day GetMonthDay(_year, _month)){_day - GetMonthDay(_year, _month);//月进位_month;//月满了if (13 _month){_year;_month 1;}}return *this;
}
我们来测试一下 对照看看我们写的是否正确 14、operator 日期天数
与 的区别在于是对对象本身而不是对对象本身的改变。所以我们需要实例化一个新的对象将传来的对象拷贝给新的对象存放天数的结果并返回。
// 日期天数
Date Date::operator(int day) const
{Date tmp(*this);tmp day;return tmp;
}
这里我们拷贝了一份之后就能复用的代码。
我们这里看看传的对象与后的对象的结果 这里我们可以看到并没有影响到d1的结果。
15、operator- 日期-天数
-是在原基础上进行修改因此隐含的this不能用const修饰因为在原基础上修改所以出了-函数体对象还在我们使用引用返回这样可以减少拷贝。
我们画图对-天数进行分析 代码实现
// 日期-天数
Date Date::operator-(int day)
{if (day 0){return *this (-day);}_day - day;while (_day 0){_month--;if (0 _month){_year--;_month 12;}_day GetMonthDay(_year, _month);}return *this;
}
运行结果 对比一下看我们实现的是否正确 16、operator- 日期-天数
-与 的逻辑是类似的-与- 的区别在于-是对对象本身-而-不是对对象本身的改变。所以我们需要实例化一个新的对象将传来的对象拷贝给新的对象存放-天数的结果并返回。
// 日期-天数
Date Date::operator-(int day) const
{Date tmp(*this);tmp - day;return tmp;
}
这里拷贝一份this之后就可以在拷贝的tmp上复用-。
我们来测试一下 17、前置后置前置--后置-- 对于前置与后置前置--与后置--它们的函数名是相同的但是实现的功能是不同的如果在符号表里找这怎么能分得清楚呢? 对于这样的问题C有自己确定的规定C规定后置重载时多增加一个int类型的参数但调用函数时该参数不用传递编译器自动传递。后置--也是如此。
这样就能实现函数重载符号表中函数名虽然相同但是一个有参数一个没参数。
下面我们对这几个函数接口分别实现
前置的规则是先再使用。因此前置就相当于1复用。
// 前置
Date Date::operator() //d1 - d1.operator()
{*this 1;return *this;
}
后置的规则是先使用再。这里我们先将this拷贝一份然后对this1返回拷贝的对象这样就做到了先使用再。
// 后置
Date Date::operator(int) //d1 - d1.operator(0)
{Date tmp(*this);*this 1;return tmp;
}
前置--的规则是先--再使用。因此前置就相当于-1复用-。
// 前置--
Date Date::operator--()
{*this - 1;return *this;
}
后置--的规则是先使用再--。这里我们先将this拷贝一份然后对this-1返回拷贝的对象这样就做到了先使用再--。
// 后置--
Date Date::operator--(int)
{Date tmp(*this);*this - 1;return tmp;
}
18、日期 - 日期返回天数
此接口是 日期-日期这里有一个存在一个小细节当 小日期-大日期 的时候返回值就是负数因此我们对这个细节要注意一点我们来对这个接口的思路梳理一遍 1、我们用假设法假设this是大日期将其赋值给max对象第二个参数是小日期将其赋值给min对象并定义一个flag初始化为 1 2、比较一下如果this是小日期那么将max、min两个对象的内容重新赋值并将flag赋值为 -1 3、定义一个计数器 n让小追大min一次计数器也追上后就跳出循环返回 n*flag 即可。 注意我们让小追大的时候使用前置虽然前置与后置都可以实现但是后置的接口中需要拷贝两次开始拷贝一次返回值会再拷贝一次前置在大量计算的时候可以实现时间与空间双重优势。 我们来实现代码
// 日期-日期 返回天数
int Date::operator-(const Date d) const
{int flag 1;Date max *this;Date min d;if (max min){max d;min *this;flag -1;}int n 0;while (min ! max){n;min;}return n * flag;
}
测试 19、const成员 将const修饰的“成员函数”称之为const成员函数const修饰类成员函数实际修饰该成员函数隐含的this指针表明在该成员函数中不能对类的任何成员进行修改。 这里我们使用 Print 接口来讲
使用const修饰后与原本的成员函数是不冲突的因为是构成重载的。
我们来看看两种版本的 Print 接口
void Date::Print()
{cout _year 年 _month 月 _day 日 endl;
}void Date::Print() const
{cout _year 年 _month 月 _day 日 endl;
}
对于打印函数来讲函数内部是不涉及修改成员的这种就是只读函数。
因此我们使用了const修饰还存在一种问题当我们的对象是const修饰如果Print函数不用const修饰在调用的时候就存在权限放大问题。
我们先将const修饰的Print函数频闭掉 我们再将const修饰的接口放开看看 总结相同函数const修饰的this与不修饰的函数构成重载
函数内部是不涉及修改成员的就是只读函数const修饰后更安全并且对于具有常属性的对象也可以兼容。