0


类和对象(中下)

文章目录

5.赋值运算符重载

5.1 运算符重载

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。

函数名字

为:关键字operator后面接需要重载的运算符符号。

函数原型

:返回值类型 operator操作符(参数列表)

注意

  1. 不能通过连接其他符号来创建新的操作符:比如operator@重载操作符必须有一个类类型参数
  2. 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义
  3. 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
  4. .* :: sizeof ?: . 注意以上5个运算符不能重载。这个经常在笔试选择题中出现。
classDate{public:Date(int year =1,int month =1,int day =1){
        _year = year;
        _month = month;
        _day = day;}//写一个公有的函数避免在类外不能使用的情况——麻烦//int GetYear()//{//    return _year;//}//直接写进类里,但是参数过多booloperator==(const Date& x){return _year == x._year
            && _month == x._month
            && _day == x._day;}private:int _year;int _month;int _day;};//bool DateEquel(Date x1, Date x2)//bool func(Date x1, Date x2)//bool riqixiangdeng(Date x1, Date x2)//{//    return x1._year == x2._year//        && x1._month == x2._month//        && x1._day == x2._day;//}//函数的类型是运算之后的返回值决定的//bool operator==(Date x1, Date x2)//第一个参数是左操作数,第二个操作数是右操作数//bool operator==(const Date& x1, const Date& x2)//{私有的在类外面不能直接访问//    return x1._year == x2._year//        && x1._month == x2._month//        && x1._day == x2._day;//}//int operator-(Date x1, Date x2)//{}intmain(){
    Date d1(2022,7,23);
    Date d2(2022,7,24);// 内置类型可以直接使用运算符运算,编译器知道要如何运算// 自定义类型无法直接使用运算法,编译器也不知道要如何运算。想支持,自己实现运算符重载即可//cout << operator==(d1,d2) << endl;//可以写自定义函数,可读性差
    cout << d1.operator==(d2)<< endl;// -> d1.operator==(&d1, d2)
    
    cout <<(d1 == d2)<< endl;//编译器会自动转换成cout << operator==(d1,d2) << endl;自定义类型://d1 < d2;//d1++;//d1 + 100;//Date d3(2022, 10, 1);//d3 - d2;return0;}classDate{public:intGetMonthDay(int year,int month){//静态区——每次访问同一个staticint days[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};//if (month == 2 && IsLeapYear(year))if(month ==2&&((year %4==0&& year %100!=0)||(year %400==0))){return29;//闰年}else{return days[month];}}Date(int year =1,int month =1,int day =1){
        _year = year;
        _month = month;
        _day = day;}booloperator==(const Date& x){return _year == x._year
            && _month == x._month
            && _day == x._day;}booloperator<(const Date& x);booloperator>(const Date& x);booloperator>=(const Date& x);booloperator<=(const Date& x);booloperator!=(const Date& x);// d1 += 100;
    Date&operator+=(int day){
        _day += day;while(_day >GetMonthDay(_year, _month)){
            _day -=GetMonthDay(_year, _month);++_month;if(_month ==13){
                _month =1;
                _year++;}}return*this;//this指针就是当前对象}// d1 + 100;日期加100天还是日期所以类型是date
    Date operator+(int day){
        Date ret(*this);
        ret._day += day;while(ret._day >GetMonthDay(ret._year, ret._month)){
            ret._day -=GetMonthDay(ret._year, ret._month);++ret._month;if(ret._month ==13){
                ret._month =1;
                ret._year++;}}return ret;}private:int _year;int _month;int _day;};intmain(){
    Date d1(2022,7,23);//Date d2(2022, 7, 24);//d1 == d2;//d1 < d2;
    Date ret = d1 +50;//Date ret(d1 + 50);/*d1 += 50;*///d1++;/*int i = 10;
    i + 50;//i不变
    i += 50;//i才变*///Date d3(20202, 10, 1);//d3 - d2;return0;}

5.2 赋值运算符重载

  1. 赋值运算符重载格式参数类型:const T&,传递引用可以提高传参效率
返回值类型

:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值,检测是否自己给自己赋值

返回*this 

:要复合连续赋值的含义

classDate{public:Date(int year =1900,int month =1,int day =1){
_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(this!=&d){
_year = d._year;
_month = d._month;
_day = d._day;}return*this;}private:int _year ;int _month ;int _day ;};
  1. 赋值运算符只能重载成类的成员函数,不能重载成全局函数原因: 赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数

《C++ prime》中说明我们可以重载赋值运算符。不论形参的类型是什么,赋值运算符都必须定义为成员函数

  1. 用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值

6.日期类的实现和前置++和后置++重载

Date.cpp
#define_CRT_SECURE_NO_WARNINGS1#include"Date.h"voidDate::Print(){
    cout << _year <<"/"<< _month <<"/"<< _day << endl;}// 任何一个类,只需要写一个> == 或者 < ==重载 剩下比较运算符重载复用即可//类作为一个整体,上下都会搜索,所以谁复用谁的顺序无所谓bool Date::operator==(const Date& d){return _year == d._year
        && _month == d._month
        && _day == d._day;}// d1 != d2  复用就可以bool Date::operator!=(const Date& d){return!(*this== d);}// d1 > d2bool Date::operator>(const Date& d){if((_year > d._year)//年大就大||(_year == d._year && _month > d._month)//年相等,月大就大||(_year == d._year && _month == d._month && _day > d._day))//年月想等,天大就大{returntrue;}else{returnfalse;}}bool Date::operator>=(const Date& d){return(*this> d)||(*this== d);}bool Date::operator<(const Date& d){return!(*this>= d);}bool Date::operator<=(const Date& d){return!(*this> d);}// d2 += 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;//this指针就是当前的自己}// d1 + 100  自己不改变,返回值是另一个对象
Date Date::operator+(int day){//Date ret(*this);
    Date ret =*this;//拷贝构造,不是赋值
    ret += day;return ret;}//反过来复用——+=会变低效,拷贝构造会变多//Date Date::operator+(int day)//{//    Date ret = *this;//    // ...//    ret._day += day;//    while (ret._day > GetMonthDay(ret._year, ret._month))//    {//        //...//    }////    return ret;//}// d1 += 100//Date& Date::operator+=(int day)//{//    *this = *this + day;////    return *this;//}

Date& Date::operator++()// 前置,返回++之后的{//*this += 1;//return *this;return*this+=1;}

Date Date::operator++(int)// 后置,返回++之前的{
    Date tmp(*this);*this+=1;return tmp;}// // 后置--

Date Date::operator--(int){

    Date ret(*this);*this-=1;return ret;}// 前置--

Date& Date::operator--(){*this-=1;return*this;//return *this -= 1;}// d1 - d2// 日期-日期 返回天数
Date Date::operator-(int day){
    Date ret =*this;//拷贝构造
    ret -= day;return ret;}

Date& Date::operator-=(int day){if(day <0){return*this+=-day;}

    _day -= day;while(_day <=0){--_month;if(_month ==0){--_year;
            _month =12;}
        _day +=GetMonthDay(_year, _month);}return*this;}//简单写法——不复用//深度复用int Date::operator-(const Date& d){int flag =1;
    Date max =*this;
    Date min = d;if(*this< d){
        max = d;
        min =*this;
        flag =-1;}int n =0;while(min != max){++min;++n;}return n*flag;}//void Date::operator<<(ostream& out)//out就是cout的别名//{//    out << _year << "-" << _month << "-" << _day << endl;//}

Date.h
#pragmaonce#include<iostream>#include<assert.h>usingnamespace std;// 一个到底可以重载哪些运算符?——> 哪些运算符对这个类型有意义classDate{//友元函数 - -在这个函数内部可以使用Date对象访问私有保护成员friend ostream&operator<<(ostream& out,const Date& d);friend istream&operator>>(istream& out, Date& d);public:// 获取某年某月的天数// 会频繁调用,所以直接放在类里面定义作为inlineintGetMonthDay(int year,int month){staticint days[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};int day = days[month];if(month ==2&&((year %4==0&& year %100!=0)||(year %400==0))){
            day +=1;}return day;}//检查日期,防止使用不合法的日期boolCheckDate(){if(_year >=1&& _month >0&& _month <13&& _day >0&& _day <=GetMonthDay(_year, _month)){returntrue;}else{returnfalse;}}// 构造会频繁调用,所以直接放在类里面定义作为inlineDate(int year =1,int month =1,int day =1){
        _year = year;
        _month = month;
        _day = day;1.//if (!this->CheckDate())//{//    Print();//    cout << "刚构造的日期非法" << endl;//}//2.assert(CheckDate());}voidPrint();booloperator==(const Date& d);booloperator!=(const Date& d);booloperator>(const Date& d);booloperator>=(const Date& d);booloperator<(const Date& d);booloperator<=(const Date& d);

    Date operator+(int day);
    Date&operator+=(int day);// ++d1;// d1++;// 直接按特性重载,无法区分// 特殊处理,使用重载区分,后置++重载增加一个int参数跟前置构成函数重载进行区分
    Date&operator++();// 前置
    Date operator++(int);// 后置

    Date&operator--();// 前置
    Date operator--(int);// 后置

    Date operator-(int day);
    Date&operator-=(int day);//日期-日期是天数intoperator-(const Date& d);/*void operator<<(ostream& out);*/private:int _year;int _month;int _day;};/*ostream& operator<<(ostream& out, const Date& d);*///流插入重载inline ostream&operator<<(ostream& out,const Date& d){
    out << d._year <<"年"<< d._month <<"月"<< d._day <<"日"<< endl;return out;}//写成inline声明和定义不分离//流提取重载inline istream&operator>>(istream& in, Date& d){
    in >> d._year >> d._month >> d._day;assert(d.CheckDate());return in;}

test.cpp
//菜单voidTestDate2(){constchar* WeeDayToStr[]={"周一","周二","周三","周四","周五","周六","周天"};

    Date d1, d2;int day =0;int option =0;do{
        cout <<"*****************************"<< endl;
        cout <<" 1.日期加、减天数  2.日期减日期"<< endl;
        cout <<" 3.日期->周几    -1.退出"<< endl;
        cout <<"*****************************"<< endl;

        cin >> option;
        cout <<"请选择:";if(option ==1){
            cout <<"请一次输入日期及天数(减天数需要输入负数):";
            cin >> d1 >> day;
            cout <<"日期加减天数后的日期:"<< d1 + day << endl;}elseif(option ==2){
            cout <<"请依次输入两个日期:";
            cin >> d1 >> d2;
            cout <<"相差的天数:"<< d1 - d2 << endl;}elseif(option ==3){
            cout <<"请输入日期:";
            cin >> d1;
            Date start(1,1,1);int n = d1 - start;int weekDay =0;// 周一
            weekDay += n;//weekDay += 9;//cout << "周" << weekDay % 7 + 1 << endl;
            cout << WeeDayToStr[weekDay %7]<< endl;}else{
            cout <<"无此选项,请重新选择"<< endl;}}while(option !=-1);}intmain(){TestDate2();return0;}
int i =0;double d =1.1;
cout << i;//cout.operator<<(i);
cout << d;//cout.operator<<(d);
  1. 库里面写好了运算符重载
  2. 自动识别类型,它们构成函数重载
运算符重载

:让自定义类型对象可以用运算符。转换成调用这个重载函数

函数重载

:支持函数名相同的函数同时存在

两者虽然都用了重载这个词,但是它们之间没有必然联系。

7.const成员

将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。

voidTestDate6(){
    Date d1(2022,7,25);const Date d2(2022,7,25);
    d1.Print();//&d1 ——> Date*
    d2.Print();//&d2 ——> const Date*

    d1 < d2;
    d2 < d1;}intmain(){TestDate6();return0;}const本身不能被修改但是有一次初始化的机会
Date*传Date*可以
const Date*传Date*属于权限的放大,不可行
voidDate::Print()//Date* const this{
    cout << _year <<"/"<< _month <<"/"<< _day << endl;}bool Date::operator<(const Date& d)///Date* const this{return!(*this>= d);}
修改:
voidDate::Print()const//const修饰的是this指针指向的内容{this->_year =1;//报错,不能被修改
    cout << _year <<"/"<< _month <<"/"<< _day << endl;}bool Date::operator<(const Date& d)const{return!(*this>= d);}

第一个也没有问题,因为Date* 传const Date*属于

权限的缩小

const修饰的是this指针指向的内容,也就是保证了成员函数内部不会修改成员变量
const对象和非const对象都可以调用这个成员函数

8.取地址及const取地址操作符重载

这两个默认成员函数一般不用重新定义 ,编译器默认会生成。

这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比
如想让别人获取到指定的内容!

classA{public:// 他们是默认成员函数,我们不写编译器会自动生成,自动生成就够用了,所以一般是不需要我们自己写的// 特殊场景:不想让别人取到这个类型对象的地址
    A*operator&(){returnnullptr;//返回空指针或者设为私有}const A*operator&()const{returnnullptr;}voidPrint()const{//_year = 1;
        cout << _year <<"/"<< _month <<"/"<< _day << endl;}/*void Print()//构成函数重载
    {
    _year = 1;
    cout << _year << "/" << _month << "/" << _day << endl;
    }*/private:int _year;// 年int _month;// 月int _day;// 日};intmain(){
    A d1;const A d2;
    d1.Print();//权限的缩小
    d2.Print();//权限的平移

    cout <<&d1 << endl;
    cout <<&d2 << endl;return0;}
标签: c++ javascript 前端

本文转载自: https://blog.csdn.net/Ll_R_lL/article/details/126128807
版权归原作者 Hey pear! 所有, 如有侵权,请联系我们删除。

“类和对象(中下)”的评论:

还没有评论