个人主页 : zxctscl
文章封面来自:艺术家–贤海林
如有转载请先通知
文章目录
- 1. 前言
- 2. 常引用
- 3. 运算符重载
1. 前言
在之前的文章中提到了常引用,再来看运算符重载之前,先来看看常引用的使用。
2. 常引用
在使用引用的时候可能会出现一些问题,例如:b是a的别名,b++,那么a肯定也加加了,但有时我们也不希望这样。
如果不希望a传过去改变,那么就得加上const
。
那么这里就能使用const加引用。
这里用到常引用,c是a的别名,但是不能修改,也就是不能通过c修改a。他是一种权限的缩小 。
这里要给x取别名,是不可以的。
因为这里权限放大,这里x是只读的,但y是x别名之后却可读可写,这是不能的。
所以加上const就可以了。
取别名不能放大权限。
权限缩小是可以的,但是权限放大是不行的。
像下面这种也是可以的。
z是常量的别名了。
还可以有这样的。
但是像下面这样就不行,因为临时变量具有常性,不能被修改。
这里是权限的放大,a+x表达式的返回值是临时对象。
如果不用const引用,如果这里传了a,那么后面的10就不能传过去,后面的表达式也不能传过去。
所以建议引用传const。
得注意:权限可以缩小,权限可以平移,但权限不能放大。
这里d可以给i,因为隐式类型转换。
但传引用就不行,因为类型不同。
但是加了const就行,为什么呢?
因为类型转换中间会有临时变量。
这里严格来说不是把d给i,然后d构造的临时变量拷贝给i。
下面的引用也是一样的,是把d拷贝给临时变量,ri是这个临时变量的别名,因为临时变量具有常性,所以用常引用。
那么为什么要产生临时变量呢?
这里i和ch比较为什么会相等?
因为i和ch不能直接去比较,在操作符两边的操作数类型不一样时,会有类型提升或截断。
这里是不能把ch扩到4个字节,所以这里会产生一个临时变量,ch不会变,变的是ch会产生的有4个字节的临时变量,4个字节把ch的值拿过去以后,按类型提升的规则,最高位也就是符号位,往上补0。a的ascii码值是97,97的最高位是0,往上补,补成4个字节,还是97。所以这里的i不是和ch比较的,而是和那个临时变量比较的。
3. 运算符重载
C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
像下面代码,要比较两个日期,不能直接比较。
内置类型就可以,是语言定义的。
自定义类型是多个类型的组合,编译器不知道怎么比较,所以不支持,需要自己来定义。
class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}//private:int _year;int _month;int _day;
};bool DateCompare(const Date& x, const Date& y)
{return x._year == y._year&& x._month == y._month&& x._day == y._day;}int main()
{Date d1(2024, 1, 1);Date d2(2024, 2, 27);cout << DateCompare(d1, d2) << endl;
如果是比较大小,像下面这样是肯定不行的,不是某一个小就小。
那么该这样写,得先比较年,年小就小,年相同后再是月,月小就小,月再相同才比较天。
bool DateCompare2(const Date& x, const Date& y)
{if (x._year < y._year){return true;}else if (x._year == y._year){if (x._month < y._month){return true;}else if (x._month == y._month){return x._day < y._day;}}return false;
}
所以自定义类型的比较得实现函数,如果函数名乱取的话,就很难判断它是用来干啥的。
为了避免这样就有了运算符重载。
函数名字为:关键字operator后面接需要重载的运算符符号。
这里的重载是指对运算符的重新定义,按照用户的需求去控制。
函数原型:返回值类型 operator操作符(参数列表)
class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}//private:int _year;int _month;int _day;
};bool operator==(const Date& x, const Date& y)
{return x._year == y._year&& x._month == y._month&& x._day == y._day;
}bool operator<(const Date& x, const Date& y)
{if (x._year < x._year){return true;}else if (x._year == x._year){if (x._month < y._month){return true;}else if (x._month == y._month){return x._day < y._day;}}return false;
}int main()
{Date d1(2024, 1, 1);Date d2(2024, 2, 27);cout << operator==(d1, d2) << endl;cout << operator<(d1, d2) << endl;cout << (operator==(d1, d2)) << endl;cout << (d1 < d2) << endl;return 0;
}
但不仅仅是这样,还有可以直接用
出现这样的情况是因为<<的优先级比==的高,加上括号就行。
为什么这里实现结果是一样的呢?
因为编译器会给去调用对应的函数。
但是在实践中私有变量肯定不是像上面代码一样。在类外面是不能访问的,那怎么办呢?
类外面不能服务,那么就放到类里面。
但不要忘记,类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this。
class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}bool operator==(const Date& y){return _year == y._year&& _month == y._month&& _day == y._day;}bool operator<(const Date& y){if (_year < y._year){return true;}else if (_year == y._year){if (_month < y._month){return true;}else if (_month == y._month){return _day < y._day;}}return false;}private:int _year;int _month;int _day;
};int main()
{Date d1(2024, 1, 1);Date d2(2024, 2, 27);cout << d1.operator==(d2) << endl;cout << d1.operator<(d2) << endl;cout << (d1 == d2) << endl; cout << (d1 < d2) << endl; return 0;
}
如果是内置类型去比较,直接转化成指令
注意:
- 不能通过连接其他符号来创建新的操作符:比如operator@
- 重载操作符必须有一个类类型参数用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this。
.*
::
sizeof
?:
.
注意以上5个运算符不能重载。这个经常在笔试选择题中出现。
有问题请指出,大家一起进步!!!