引言: 运算符是一种告诉编译器执行特定的数学或逻辑操作的符号。C++ 内置了丰富的运算符。
一、运算符
1. 算术运算符
下表显示了 C++ 支持的所有算术运算符。假设变量 A 的值为 10,变量 B 的值为 20,则:
运算符 | 描述 | 实例 |
---|---|---|
+ | 把两个操作数相加 | A+B将得到30 |
- | 从第一个操作数中减去第二个操作数 | A-B将得到-10 |
* | 把两个操作数相乘 | A*B将得到200 |
/ | 分子除以分母 | B/A将得到2 |
% | 取模运算符,整除后的余数 | B%A将得到0 |
++ | 自增运算符,整数值增加1 | A++将得到11 |
– | 自减运算符,整数值减少1 | A–将得到9 |
2. 关系运算符
下表显示了 C++ 支持的所有关系运算符。同样还是假设变量 A 的值为 10,变量 B 的值为 20,则:
运算符 | 描述 | 实例 |
---|---|---|
== | 检查两个操作数的值是否相等,如果相等则条件为真。 | (A==B)不为真。 |
!= | 检查两个操作数的值是否相等,如果不相等则条件为真。 | (A!=B)为真。 |
> | 检查左操作数的值是否大于右操作数的值,如果是则条件为真。 | (A>B)不为真。 |
< | 检查左操作数的值是否小于右操作数的值,如果是则条件为真。 | (A<B)为真。 |
>= | 检查左操作数的值是否大于或等于右操作数的值,如果是则条件为真。 | (A>=B)不为真。 |
<= | 检查左操作数的值是否小于或等于右操作数的值,如果是则条件为真。 | (A<=B)为真。 |
3. 逻辑运算符
下表显示了 C++ 支持的所有关系逻辑运算符。假设变量 A 的值为 1,变量 B 的值为 0,则:
运算符 | 描述 | 实例 |
---|---|---|
&& | 称为逻辑与运算符。如果两个操作数都非零,则条件为真。 | (A&&B)为假。 |
|| | 称为逻辑或运算符。如果两个操作数中有任意一个非零,则条件为真。 | (A |
! | 称为逻辑非运算符。用来逆转操作数的逻辑状态。如果条件为真则逻辑非运算符将使其为假。 | !(A&&B)为真。 |
需要注意的是&&和||存在短路情况。&&:有一个假则为假,所以如果前面一个变量为假,那么就直接为假,后面的不做处理了。||:有一个真则为真,所以如果前面一个变量为真,那么就直接为真,后面的不做处理了。
4. 位运算符
下表显示了 C++ 支持的位运算符。假设变量 A 的值为 60,变量 B 的值为 13,现在以二进制格式表示:A = 0011 1100,B = 0000 1101。则:
运算符 | 描述 | 实例 |
---|---|---|
& | 如果同时存在于两个操作数中,二进制AND运算符复制一位到结果中。 | (A&B)将得到12,即为0000 1100 |
| | 如果存在于任一操作数中,二进制OR运算符复制一位到结果中。 | (A|B)将得到61,即为0011 1101 |
^ | 如果存在于其中一个操作数中但不同时存在于两个操作数中,二进制异或运算符复制一位到结果中。 | (A^B)将得到49,即为0011 0001 |
~ | 二进制补码运算符是一元运算符,具有"翻转"位效果。 | (~A)将得到-61,即为1100 0011,2的补码形式,带符号的二进制数。 |
<< | 二进制左移运算符。左操作数的值向左移动右操作数指定的位数。 | A<<2将得到240,即为1111 0000 |
>> | 二进制右移运算符。左操作数的值向右移动右操作数指定的位数。 | A>>2将得到15,即为0000 1111 |
5. 赋值运算符
下表列出了 C++ 支持的赋值运算符:
运算符 | 描述 | 实例 |
---|---|---|
= | 简单的赋值运算符,把右边操作数的值赋给左边操作数 | C=A+B将把A+B的值赋给C |
+= | 加且赋值运算符,把右边操作数加上左边操作数的结果赋值给左边操作数 | C+=A相当于C=C+A |
-= | 减且赋值运算符,把左边操作数减去右边操作数的结果赋值给左边操作数 | C-=A相当于C=C-A |
*= | 乘且赋值运算符,把右边操作数乘以左边操作数的结果赋值给左边操作数 | C=A相当于C=CA |
/= | 除且赋值运算符,把左边操作数除以右边操作数的结果赋值给左边操作数 | C/=A相当于C=C/A |
%= | 求模且赋值运算符,求两个操作数的模赋值给左边操作数 | C%=A相当于C=C%A |
<<= | 左移且赋值运算符 | C<<=2等同于C=C<<2 |
>>= | 右移且赋值运算符 | C>>=2等同于C=C>>2 |
&= | 按位与且赋值运算符 | C&=2等同于C=C&2 |
^= | 按位异或且赋值运算符 | C ^= 2等同于C=C^2 |
|= | 按位或且赋值运算符 | C|=2等同于C=C|2 |
6. 杂项运算符
下表列出了 C++ 支持的其他一些重要的杂项运算符。
运算符 | 描述 |
---|---|
sizeof | sizeof运算符返回变量的大小。例如,sizeof(a)将返回4,其中a是整数。 |
Condition?X:Y | 条件运算符。如果Condition为真?则值为X:否则值为Y。 |
, | 逗号运算符会顺序执行一系列运算。整个逗号表达式的值是以逗号分隔的列表中的最后一个表达式的值。 |
.(点)和->(箭头) | 成员运算符用于引用类、结构和共用体的成员。 |
Cast | 强制转换运算符把一种数据类型转换为另一种数据类型。例如,int(2.2000)将返回2。 |
& | 指针运算符&返回变量的地址。例如&a;将给出变量的实际地址。 |
* | 指针运算符*指向一个变量。例如,*var;将指向变量var。 |
以上摘自:https://www.sojson.com/operation/cxx.html
二、运算符优先级
优先级 | 运算符 | 描述 | 例子 | 结合性 |
---|---|---|---|---|
1 | () [] -> . :: ++ -- | 调节优先级的括号操作符 数组下标访问操作符 通过指向对象的指针访问成员的操作符 通过对象本身访问成员的操作符 作用域操作符 后置自增操作符 后置自减操作符 | (a+b)/4; array[4]=2; ptr->age=34; obj.age=34; Class::age=2; for(i=0;i<10;i++)... for(i=10;i>0;i--)... | 从左到右 |
2 | ! ~ ++ -- - + * & (type) sizeof | 逻辑取反操作符 按位取反(按位取补) 前置自增操作符 前置自减操作符 一元取负操作符 一元取正操作符 解引用操作符 取地址操作符 类型转换操作符 返回对象占用的字节数操作符 | if(!done)... flags=~flags; for(i=0;i<10;++i)... for(i=10;i>0;--i)... int i=-1; int i=+1; data=*ptr; address=&obj; int i=(int)floatNum; int size=sizeof(floatNum); | 从右到左 |
3 | ->* .* | 在指针上通过指向成员的指针访问成员的操作符 在对象上通过指向成员的指针访问成员的操作符 | ptr->*var=24; obj.*var=24; | 从左到右 |
4 | * / % | 乘法操作符 除法操作符 取余数操作符 | int i=2*4; float f=10/3; int rem=4%3; | 从左到右 |
5 | + - | 加法操作符 减法操作符 | int i=2+3; int i=5-1; | 从左到右 |
6 | << >> | 按位左移操作符 按位右移操作符 | int flags=33<<1; int flags=33>>1; | 从左到右 |
7 | < <= > >= | 小于比较操作符 小于或等于比较操作符 大于比较操作符 大于或等于比较操作符 | if(i<42)... if(i<=42)... if(i>42)... if(i>=42)... | 从左到右 |
8 | == != | 等于比较操作符 不等于比较操作符 | if(i==42)... if(i!=42)... | 从左到右 |
9 | & | 按位与操作符 | flags=flags&42; | 从左到右 |
10 | ^ | 按位异或操作符 | flags=flags^42; | 从左到右 |
11 | | | 按位或操作符 | flags=flags|42; | 从左到右 |
12 | && | 逻辑与操作符 | if(conditionA&&conditionB)... | 从左到右 |
13 | || | 逻辑或操作符 | if(conditionA||conditionB)... | 从左到右 |
14 | ?: | 三元条件操作符 | int i=(a>b)?a:b; | 从右到左 |
15 | = += -= *= /= %= &= ^= |= <<= >>= | 赋值操作符 复合赋值操作符(加法) 复合赋值操作符(减法) 复合赋值操作符(乘法) 复合赋值操作符(除法) 复合赋值操作符(取余) 复合赋值操作符(按位与) 复合赋值操作符(按位异或) 复合赋值操作符(按位或) 复合赋值操作符(按位左移) 复合赋值操作符(按位右移) | int a=b; a+=3; b-=4; a*=5; a/=2; a%=3; flags&=new_flags; flags^=new_flags; flags|=new_flags; flags<<=2; flags>>=2; | 从右到左 |
16 | , | 逗号操作符 | for(i=0,j=0;i<10;i++,j++)... | 从左到右 |
以上摘自:http://www.jsons.cn/levelcadd/
三、单目运算符 双目运算符 三目运算符
- 单目运算符:只有一个操作数,例如:逻辑非运算符【!】、按位取反运算符【~】、自增自减运算符【++ --】、负号运算符【-】、类型转换运算符【(类型)】、指针运算符和取地址运算符【*和&】、长度运算符【sizeof】这些是单目运算符。
- 双目运算符:有两个操作数,例如:,+,-,*,/,=,== 等等
- 三目运算符:需要三个操作数,例如:?:
四、运算符重载
1. 什么是运算符的重载?
运算符与类结合,产生新的含义。
2. 为什么要引入运算符重载?
作用:为了实现类的多态性(多态是指一个函数名有多种含义)
3. 怎么实现运算符的重载?
- 方式:类的成员函数 或 友元函数(类外的普通函数)
- 规则:不能重载的运算符有". "和 ".* "和 “?:” 和 ":: "和 “sizeof”
1) 友元函数和成员函数的使用场合
一般情况下,建议一元运算符使用成员函数,二元运算符使用友元函数。
- 运算符的操作需要修改类对象的状态,则使用成员函数。如需要做左值操作数的运算符(如=,+=,++)
- 运算时,有数和对象的混合运算时,必须使用友元
- 二元运算符中,第一个操作数为非对象时,必须使用友元函数。如输入输出运算符<<和>>
具体规则如下:
运算符 | 建议使用 |
---|---|
所有一元运算符 | 成员函数 |
= ( ) [ ] -> | 必须是成员函数 |
+= -= /= *= ^= &= != %= >>= <<= , 似乎带等号的都在这里了 | 成员函数 |
所有其它二元运算符, 例如: –,+,*,/ | 友元函数 |
<< >> | 必须是友元函数 |
2) 参数和返回值
当参数不会被改变,一般按const引用来传递(若是使用成员函数重载,函数也为const).
对于返回数值的决定:
- 如果返回值可能出现在=号左边, 则只能作为左值, 返回非const引用。
- 如果返回值只能出现在=号右边, 则只需作为右值, 返回const型引用或者const型值。
- 如果返回值既可能出现在=号左边或者右边, 则其返回值须作为左值, 返回非const引用。