文章目录
- 3 运算符
- 3.1 表达式
- 3.1.1 基本概念
- 3.1.2 运算符和运算对象
- 3.1.3 运算对象的转换
- 3.1.4 左值和右值
- 3.2 运算符
- 3.2.1 算术运算符
- 3.2.2 赋值运算符
- 3.2.3 比较运算符
- 3.2.4 逻辑运算符
- 3.2.5 成员访问运算符
- 3.2.6 条件运算符
3 运算符
C++提供了一套供操作内置数据类型的运算符,当然,对于不是内置数据类型的数据对象,C++也允许程序员进行运算符重载,使运算符赋予新的含义。在这一讲中,我们不会谈论关于运算符重载的知识,但是我们会谈谈如何使用运算符来操作内置数据类型。
3.1 表达式
3.1.1 基本概念
表达式由一个或多个运算对象 组成,对表达式求值将得到一个结果。如下所示:
int a,b;
int c = a + b;//一个表达式含有多个数据对象
当然,上述的演示可以进行有限次的加减乘除,对于一些特定的数据对象,还可以直接让字面值和变量进行加减乘除使之构成表达式。
3.1.2 运算符和运算对象
C++定义了一元运算符
和二元运算符
。顾名思义,多少元的运算符就可以同时操纵多少个数据对象。如在后续我们会学习的取地址符&
和解引用符*
,这些都是作用在一个数据对象上的;而本节将会讨论的如算术运算符加减乘除这些都是同时操作两个数据对象。
多个含义
一个运算符可能在不同的语义下会有多个含义,如*运算符用在指针时表示解引用,而用于两个基本数据对象时表示两个基本数据对象做乘法。
3.1.3 运算对象的转换
在表达式的求值中,常常会出现一些类型经过表达式的求值后变为另外一种类型的情况。
敲一下下面的代码,仔细体会我说的内容:
#include <iostream>
#include <typeinfo>
using namespace std;int main()
{double a = 1.9;int b = 1;auto c = a + b;cout << typeid(c).name() << endl;
}
out:
查看对象的数据类型
如同python的type()方法一般,C++也可以查看对象的数据类型,如果想要查看对象的数哦据类型,需导入typeinfo()标准库,并且调用库中的typeid()方法,将对象作为参数传入,再调用name()方法即可查看对象的数据类型。
3.1.4 左值和右值
C++的表达式要不然是右值,要不然是左值,这两个术语是从C继承过来的。
如果是左值,那么其可以出现在表达式等号的左侧,反之如果是右值,则不可出现在等号左侧。
左值和右值还有另外一层含义,如果一个对象作为右值,那么其是作为内容来使用的,而一个对象作为左值时,那么其相当于一个身份。如:
int a = 10;//10是内容,而a相当于其身份,当你叫a时,实际上就是在叫10这个字面值
int b = a;//a是内容,b相当于其身份,当你叫b时,实际上是在叫a这个对象中的内容
3.2 运算符
3.2.1 算术运算符
作用:用于处理四则运算
算术运算符包括以下符号:
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
+ | 正号 | +3 | 3 |
- | 负号 | -3 | -3 |
+ | 加 | 10+5 | 15 |
- | 减 | 10-5 | 5 |
* | 乘 | 10*5 | 50 |
/ | 除 | 10/5 | 2 |
% | 取模(取余) | 10%3 | 1 |
++ | 前置递增 | a = 2;b = ++a; | a = 3;b = 3; |
++ | 后置递增 | a = 2;b = a++; | a = 3;b = 2; |
__ | 前置递增 | a = 2;b = --a; | a = 1;b = 1; |
– | 后置递增 | a = 2;b = a– | a = 1;b = 2; |
注意
%运算符求模,他要求两个操作数必须都是整型,将该运算符用于浮点数将导致编译错误。
还有一个需要提醒的是
环绕现象
。如果一个表达式通过运算后得出的结果超出了数据类型规定的范围,那么他就会发生环绕现象。举个例子,如int类型,其值范围为(-2^31 ~ 2^ 31-1)。我们来看看当表达式的结果为2312^{31}231,且结果数据类型恰好设定为int会发生什么事。
#include <iostream> #include <typeinfo> using namespace std;int main() {int a = pow(2,31)-1;cout << a << endl;int b = a + 1;cout << b << endl; }
out:
这就是环绕现象,这下你应该深有体会了。
示例:加减乘除
#include <iostream>using namespace std;
int main()
{//加减乘除int a1 = 10;int b1 = 3;cout << a1 + b1 << endl;cout << a1 - b1 << endl;cout << a1 * b1 << endl;cout << a1 / b1 << endl;//两个整数相除,结果依然是整数,并且这个整数是将小数部分去除的结果int a3 = 10;int b3 = 0;//cout << a3 / b3 << endl;//报错,除数不能为0double a2 = 10.0;double b2 = 3.0;cout << a2 / b2 << endl;system("pause");return 0;
}
out:
运算顺序
一条表达式中含有多个算数运算符时,这时候就涉及到各种优先级问题。但是在实际开发中,如果你记不起各种运算符的优先级,那么使用小括号括起使其先行运算是一个不错的选择,因为括号可以无视优先级和结合律。
示例二:取模运算
#include <iostream>
using namespace std;
int main()
{int a1 = 10;int b1 = 3;cout << 10 % 3 << endl;int a2 = 10;int b2 = 20;cout << a2 % b2 << endl;int a3 = 10;int b3 = 0;//cout << a3 % b3 << endl;//取值运算时,除数也不能为0//两个小数不可以取模double d1 = 3.14;double d2 = 1.1;//cout << d1 % d2 << endl;}
out:
示例三:前置递增和后置递增
#include <iostream>
using namespace std;int main()
{//1、前置递增int a = 10;++a;//让变量+1cout << "a = " << a << endl;//2、后置递增int b = 10;b++;cout << "b = " << b << endl;//3、前置后置的区别//前置递增 先让变量+1然后进行表达式运算int a2 = 10;int b2 = ++a2 * 10;cout << "a2 = " << a2 << endl;cout << "b2 = " << b2 << endl;//后置递增 先进行表达式运算,然后让变量+1int a3 = 10;int b3 = a3++ * 10;cout << "a3 = " << a3 << endl;cout << "b3 = " << b3 << endl;system("pause");return 0;
}
out:
3.2.2 赋值运算符
赋值运算符用于将右边的数据对象赋给左边的数据对象。不过需要注意的是,左边的数据对象(左值)必须可修改。
对于将字面值赋给变量,我们一般不叫赋值而叫初始化
。如:
int a = 10;
有一些操作是非法的,这些都是在使用的时候需要去潜移默化的去了解,如常量是不可以作为左值的,字面值是不可以作为左值的,算术表达式是不可以作为左值的。
C++11新标准允许我们使用花括号括起的初始值列表。当然这个知识前面已经讲过,这里不再赘述。
需要注意的是,很多人常常会混淆赋值运算符=
和相当运算符==
。
3.2.3 比较运算符
比较运算符用于表达式的比较,并返回一个真值或假值。有时候比较运算符也叫关系运算符
。比较运算符有以下符号:
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
== | 相等于 | 4==3 | 0 |
!= | 不等于 | 4!=3 | 1 |
< | 小于 | 4<3 | 0 |
> | 大于 | 4>3 | 1 |
<= | 小于等于 | 4<=3 | 0 |
>= | 大于等于 | 4>=3 | 1 |
3.2.4 逻辑运算符
逻辑运算符用于根据表达式的值返回真值或假值,其类下有以下符号:
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
! | 非 | !a | 如果a为假,则!a为真;如果a为真,则!a为假。 |
&& | 与 | a&&b | 如果a和b都为真,则结果为真,否则为假。 |
|| | 或 | a||b | 如果a和b有一个为真,则结果为真,两者都为假时,结果为假。 |
示例1:逻辑非
#include <iostream>
using namespace std;int main()
{//逻辑运算符 非!int a = 10;//在C++中,除了0都为真cout << !a << endl;system("pause");return 0;
}
3.2.5 成员访问运算符
这个实际上如果你不理解可以等学完面向对象的那几讲后再回来看也不迟。
点运算符.
和箭头运算符->
都可以用于访问对象的成员。
不过需要注意的一点是,解引用运算符的优先级低于点运算符。所以执行解引用运算的子表达式两端必须加上括号,如果没有括号含义就变了。
*p.size(); //错误,p是一个指针,它没有名为size的成员。
*(p.size()); //正确。
3.2.6 条件运算符
条件运算符在python中时常被称作三目运算符,但是我不知道在C++中有无类似的叫法。条件运算符允许我们将if-else的逻辑嵌入到单个表达式中,其表达十分简洁。格式如下:
判断语句?结果1:结果2
上述的表达式表达了这么个意思:如果判断语句为真,那么表达式的值为结果1,否则为结果2。
条件运算符允许嵌套,但是,随着嵌套的层数增加,代码的可读性也变差,所以一般我们不要这么做去嵌套哈。