1.3 运算符
C++内置了一些运算符(operator),使用这些运算符能够满足基本的计算需要,若要增强运算符的功能,扩展运算符的应用范围,可使用C++的运算符重载功能,如加号(+)只能用于基本类型之间的运算,若要实现两个字符串的相加,如“abc”+“def”得到“abcdef”,由于字符串不是基本数据类型,需要对字符串类重载加号运算符operator +,以实现特定功能。
1.3.1 算术运算符
算术运算符用于常见的数学运算,如加(+)、减(-)、乘(*)、除(/)、求余(%),其中求余运算要求为两个整数,即int%int。若参与运算的两个数精度不同,低精度的数自动转换为相同的高精度数,如double/int运算,int自动提升为double类型。优先级规则同一般的数学运算,可使用括号()。
【实例1-7】输出两个整数加、减、乘、除、求余的结果。
#include <iostream> using namespace std; int main() { int a1=1500; int a2=300; cout<<"相加:"<<a1+a2<<endl; cout<<"相减:"<<a1-a2<<endl; cout<<"相乘:"<<a1*a2<<endl; cout<<"相除:"<<a1/a2<<endl; cout<<"求余:"<<a1%a2<<endl; return 0; }
编译运行,结果如图1-9所示。
图1-9 算术运算
1.3.2 关系运算符
关系运算符用于比较两个变量的大小,如大于(>)、小于(<)、等于(==)、大于等于(>=)、小于等于(<=)、不等于(!=),关系运算结果为true或false,常用于逻辑判断。
【实例1-8】输出两个关系表达式的结果。
#include <iostream> using namespace std; int main() { double d1=1.0/99999; //极小的浮点值 cout<<d1<<"==0 结果:"<<(d1==0)<<endl; //是否等于0 cout<<d1<<"> 0 结果:"<<(d1>0)<<endl; //是否大于0 return 0; }
编译运行,结果如图1-10所示。浮点值总不等于0,应避免浮点值和0的相等比较。
图1-10 关系运算符
1.3.3 赋值运算符
赋值运算符(=)用于将运算符右边的值赋给左边的变量,两个连续的等号(==)表示等于关系,要小心区别。赋值运算符与算术运算符结合可简化代码,如a=a+2;可简化为a+=2;类似的有-=、*=、/=、%=。
赋值运算符两边的数据类型应一致,或右边的类型可自动转换为左边的类型,否则需要强制类型转换,如double b=0.01; int a=(int)b;。double类型不会自动转换为低精度的int类型,需要使用(int)进行强制类型转换。
一般情况下,低精度类型可以自动转换为高精度,高精度向低精度转换需要强制转换。强制转换在C和C++中有所不同,C语言在括号中放入要转换的类型,如int a=(int)b; C++语言在括号中放入要转换的变量或表达式,如int a=int(b);由于C++完全兼容C,因此在C++中两种方式都可以使用。
【实例1-9】输出两整数、浮点数与整数相除的结果,以及*=自乘运算结果。
#include <iostream> using namespace std; int main() { int a=7; //赋初值 double b1=a/22; //两整数相除 double b2=(double)a/22; //强制转换为浮点数后相除 cout<<"b1 "<<b1<<endl; cout<<"b2 "<<b2<<endl; b2*=100; //自乘100 cout<<"b2*100 "<<b2<<endl; return 0; }
编译运行,结果如图1-11所示。(double)a强制将a的值转为double类型,在括号内写入要转换的类型,也可使用double(a)形式进行转换。
图1-11 赋值运算符
1.3.4 自增自减运算符
自增(++)自减(--)运算符用于将变量增加或减去1,如a++、a--、++a、--a,运算符在变量后(a++、a--)先以a的当前值运算,再对a自增或自减。若在变量前(++a、--a)先对a自增或自减,以变化后的a参与计算。若为一个单独的表达式,如a++; ,则在前在后没有区别。
【实例1-10】输出自增、自减运算结果。
#include <iostream> using namespace std; int main() { int a=0; int b=a++; //将当前值0赋给b,然后自增1 cout<<"a++ "<<b<<endl; cout<<"a "<<a<<endl; int c=--a; //先自减1,然后将值赋给c cout<<"--a "<<c<<endl; cout<<"a "<<a<<endl; return 0; }
编译运行,结果如图1-12所示。程序代码的可读性非常重要,使用int b=a++;这种形式的语句无形中提高了阅读的难度,把简单的事情复杂化,为提高程序的易读性,建议拆分为int b=a; a++;而int c=--a;可拆分为int c=a-1; a--;将a--当做a=a-1的一种简写方式。
图1-12 自增自减运算符
1.3.5 逻辑运算符
逻辑运算符用于关系表达式的组合,如与(&&)、或(||)、非(!),常用于条件的逻辑判断。
❑ 要求多个条件同时成立,使用&&。若前面的表达式为假,则停止判断后面的表达式。
❑ 要求至少一个条件成立,使用||。若前面的表达式为真,则停止判断后面的表达式。
❑ 要求条件的对立面成立,使用!。
【实例1-11】输出用逻辑运算符连接的多个关系表达式的结果。
#include <iostream> using namespace std; int main() { bool b1=(12>=5 && 1<0); //与,要求全部为true bool b2=(1/7==0 || -1>=0); //或,要求至少一个为true bool b3=(!b1); //非,true的对立面为false cout<<"b1 "<<b1<<endl; cout<<"b2 "<<b2<<endl; cout<<"b3 "<<b3<<endl; return 0; }
编译运行,结果如图1-13所示。若一个逻辑判断表达式中有多个逻辑运算符,建议使用括号提高可读性,尽量不要依赖逻辑运算符的优先级,代码是让人来读的,以易读为第一标准。
图1-13 逻辑运算符
1.3.6 位运算符
计算机存储数据的最小单位是位(bit),位运算符用于位级别的数据计算,包括位移运算符左移(<<)、右移(>>),位逻辑运算符与(&)、或(|)、异或(^)、非(~)。
位移运算符移动位数据的位置,例如十进制整数10用二进制表示为1010。
❑ 将10右移1位(10>>1)后,变为0101即5。
❑ 将10右移2位(10>>2)后,变为0010即2。
❑ 将10左移1位(10<<1)后,变为10100即20。
位逻辑运算符根据每个位的值进行逻辑运算,例如十进制整数10用二进制表示为1010,十进制整数2用二进制表示为0010。
❑ 与运算(&):若对应位都为1,结果为1,否则为0,10&2结果为0010。
❑ 或运算(|):若对应位有一个为1,结果为1,否则为0,10|2结果为1010。
❑ 异或运算(^):若对应位一个为1,一个为0,结果为1,否则为0,10^2结果为1000。
❑ 非运算(~):若对应位为1,变为0,若为0,变为1,~10的结果为0101。
【实例1-12】输出左移、右移,以及与、或、异或、非的位运算结果。
#include <iostream> using namespace std; int main() { cout<<"10<<1 "<<(10<<1)<<endl; //左移1 cout<<"10>>1 "<<(10>>1)<<endl; //右移1 cout<<"10&2 "<<(10&2)<<endl; //与 cout<<"10|2 "<<(10|2)<<endl; //或 cout<<"10^2 "<<(10^2)<<endl; //异或 cout<<"~10 "<<(~10)<<endl; //非 return 0; }
编译运行,结果如图1-14所示。左移一位相当于乘以2,右移一位相当于除以2。
图1-14 位运算符
Tips 位运算常用于参数属性的标志位,如一个标志参数用二进制表示为10010001,每个位代表一种特定的属性,位若为1表示使用该位所代表的属性,若为0表示不使用,如用CFile类调用Open函数打开文件时指定CFile::modeCreate|CFile:: modeWrite两个标志,用位或运算符相连,则这两个标志所对应位的值为1,其余位都为0。