做海报用的图片网站,个人网站用什么建站程序,网络seo公司,南京网络推广优化哪家好【C】运算符重载#xff08;日期类的实现#xff09; 前言运算符重载operator全局和类中 日期类的实现成员变量的确定构造函数拷贝构造 运算符重载部分的重载思路实现GETmonthdayoperator 的重载思路实现 -的与-的重载实现 各个比较运算符的重载实现 前置与后置实现 #xf… 【C】运算符重载日期类的实现 前言运算符重载operator全局和类中 日期类的实现成员变量的确定构造函数拷贝构造 运算符重载部分的重载思路实现GETmonthdayoperator 的重载思路实现 -的与-的重载实现 各个比较运算符的重载实现 前置与后置实现 赋值运算符的重载实现 后话 前言 博主在快写完类和对象中时突然发现需要用到运算符重载的知识 但是运算符有很多运算符要进行重载会导致文章的篇幅略长 所以就单独写了一个另外日期类是学习运算符重载比较好的一个例子所以这里就用了日期类来讲解运算符重载 运算符重载
众所周知对于内置类型我们可以直接使用运算符进行计算 int y1, int x1 xy 这显然是可以的
那自定义类型可不可以直接用运算符来算呢 比如 stack s1; stack s2; s1s2
当然是不可以的
这不是显而易见吗 现在编译器也不至于聪明到能直接分辨出用户的自定义类型的运算。 要是编译器真的高级到这个程度那就是更高级的语言了
但是类如果要进行加减乘除的时候又要进行函数的调用
如果能直接用加减乘除等操作符的话那不是能大大增强函数的可读性吗
所以就有了关键字
operator
运算符重载函数的形式为 void返回类型operator(需要重载的运算符)参数 例
Date operator(int x);这里在使用operator进行重载时 有几个点需要注意
1.不可以用operator重载一个原本没有意义的符号。
如operator
2.运算符重载必须有一个自定义类型的对象
因为本来运算符重置就是为了自定义类而创建 要是没有自定义类的对象参数 那还有啥意义。 这五个运算符不能进行重载。
4.讲了很多次 自定义类型深究到最后也就只是内置类型
所以当我们编写运算符重载函数的时候 内置类型的运算符含义不能进行改变
你想改也改不了。
全局和类中
这里来给大家提个问题全局和类有啥区别
1. 全局中的函数无法随意调用类中的私人成员 就会出现这样尴尬的场面这里有解决方法但是还是留在之后讲
但是如果将运算符重载函数写在类中就可以随意调用了。
2. 类中有this指针这个存在
这意味着运算符重载在全局和类中有不同的定义方式
上面我们看到了
全局对象需要完全地写出参数
但是在类中的函数因为有this指针的隐形传参所以不需要将全部参数写出来
class Date
{Date operator(int day) {}
}这里this指针将对象的地址传了过去
所以不需要像全局变量一样传一个类的对象形参
所以为了方便还是尽量讲运算符重载函数写在类中。
日期类的实现
日期算是我们生活中常见的了。
成员变量的确定
由 年-月-日组成
所以我们这里针对成员变量的设计也是十分容易
class Date
{
private:int _year;int _month;int _day;
};构造函数
还记得我们这里要创建构造函数的原因吗
因为date类中全是内置类型 编译器自动生成的默认构造函数不会对内置类型变量进行设定。 所以遇到内置类型就要自己写构造函数了
这里就写个缺省的和无参的
//缺省Date(int year,int month,int day){_year year;_month month;_day day;}//无参
Date()
{_year 2023;_month 5;_day 24;
}拷贝构造
因为拷贝构造属于构造函数里的这里就直接把它放在这里了
Date::Date(const Date d)
{_year d._year;_month d._month;_day d._day;
}运算符重载部分
这个部分算是正式进入我们的正题了
这里的函数我都默认放在类中进行实现的。
的重载
这里要实现的功能是
日期天数 返回新日期
注意这个运算符号是原本就是要对前一个值进行改变的。 所以我们这里就是对 原对象进行然后返回原对象就好
这里理解起来很容易但是要实现起来的话还是有点小繁琐的。
思路
想要得到日期天数转化为日期。
1.首先要得到知道每个月的天数
2.将现在日期的天数和传参的天数相加
3.判断现在天数是否大于这个月应有的天数
若大于 扣除每个月对应的天数然后月份1
若小于 则日期已经完成直接返回就好
实现
我们要知道所在的这个月的天数所以我们需要设定一个函数专门用来返回当月的对应的天数
GETmonthday
int GETmonthday(int year, int month)
{static int arr[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;}return arr[month];
}这里通过静态数组将每个月对应的天数存储下来 (因为这个函数在后续需要多次调用所以使用静态数组防止多次开辟空间影响效率)
通过传来的年月来进行 闰年/平年 对应月 的判断 得到对应的天数后返回。
operator
//这里返回值用了引用因为返回的就是原对象函数结束后没有随着函数被销毁。
Date operator(int day)
{_day day;//将天数和天数相加while (_day this-GETmonthday(_year,_month))//当现有天数大于本月总天数程序继续{_day - GETmonthday(_year, _month);_month;//天数减去这个月对应天数当前月份if (_month 12)//当月份大于12时年当前月份变为1{_month 1;_year;}}return *this;//返回改变后的天数
}的重载
思路
和有啥区别
对原对象进行了改变并且返回的也是原对象
而 就不一样了 不会对原对象进行赋值改变 并且返回的是原对象与天数相加后的新对象
实现
这里搞懂了区别后就可以进行实现了
这里就会发现 其实和中间的对象与天数相加的思路一样 就是需要 1.返回新对象 2.原对象不能进行改变。
Date operator(int day)
{
//用原对象进行了拷贝构造出了tmpDate tmp(*this);//将tmp进行用的是之前实现的重载tmp day;
//返回tmpreturn tmp;
}-的与-的重载
这里其实思路和与的重载相似所以这里就不多讲了 因为这篇博客主要是想讲清不同运算符重载的实现
实现
//-的实现
Date operator-(int day)
{_day - day;while (_day 0){_day GETmonthday(_year, _month);_month--;if (_month 1){_month 12;_year--;}}return *this;
}
}
//-的实现
Date operator-(int day)
{Date tmp(*this);tmp - day;return tmp;
}各个比较运算符的重载
这里比较运算符算是最简单的运算符重载了
传入一个Date类对象 和this指针的本对象进行年月日比较 最后返回布尔值即可
实现
//的实现
bool operator(const Date d)
{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;return false;
}//大于的实现
bool operator(const Date d)
{return ((!(*this d)) (!(*this d )));
}//等于的实现
bool operator(const Date d)
{return _day d._day _year d._year _month d._month;
}
//大于等于的实现
bool operator(const Date d)
{return !(*this d);
}
//小于等于的实现
bool operator(const Date d)
{return !(*this d);
}
//不等于的是实现
bool operator!(const Date d)
{return !(*this d);}前置与后置
这里还是和之前一样来搞清楚这两个的区别
前置
直接对象1然后返回对象值即可
后置 先返回对象的原值然后对象值 这里的实现思路肯定不是这样return值了以后函数就结束怎么还能
所以这里就要用原对象创建新对象 对原对象返回创建的新对象
搞清楚思路了以后接下来还有个问题
区分两者
还记的运算符重载的命名方式吗
void返回类型operator(需要重载的运算符)参数
但是前置和后置都是运算符
所以定义时都是operator
这就不好区分了
但是祖师爷在定义的时候就发现
自增运算符都是对单个对象的运算
所以传参时不需要传任何参数 原对象this指针会进行传递
那让编译器给前置运算符或者前置运算符 随便传一个参数不就可以识别了吗
所以选择了后置
Date Date::operator()
//前置
Date Date::operator(int)
//后置
//用户自己声明时要在后置运算符加上int参数实现
//前置
Date Date::operator()
{return (*this 1);
}//后置
Date Date::operator(int)
{Date tmp(*this);*this 1;return tmp;
}所以从上面的实现中可以看出
当我们用自定义类型的时最好使用前置
因为后置需要创建一个新对象会影响效率。
同样对于内置类型前置和后置
虽然也大致是这样的原理 前置比后置更加有效率 但是因为内置类型拷贝成本比较低 所以没有特意去区分前置和后置的使用
赋值运算符的重载
我们知道赋值运算符也是默认成员函数之一 就是用户不写时编译器会自己生成。
目的将一个对象的值赋值给另一个对象
实现 这个赋值构造函数可能看着没啥问题
但是别忘了对于内置类型来说赋值能这样做
xyca 能做到这样的连续赋值。
但是我们的这个实现方法不能进行连续赋值
原因就在于 返回类型为空。
所以这里需要把赋值后的原对象进行返回
Date operator(Date d1)
{_year d1._year;_day d1._day;_month d1._month;return (*this);
}后话
这里其实还有很多内容没有去实现。
比如说 对象与对象的运算符 后置–与前置– 但是这里主要是想带大家学习一下重载运算符而已 所以这个日期类就点到为止。