C++ Primer 第4章 表达式(1)

第4章 表达式

C++语言提供了一套丰富的运算符,并定义了这些运算符作用在内置类型的运算对象时所执行的基本操作。当运算对象时类类型时,C++语言也允许用户指定上述运算符的含义。
表达式由一个或多个运算对象组成,对表达式求值将得到一个结果。字面值和变量是最简单的表达式,其结果就是字面值和变量的值。把一个运算符和一个或多个运算对象组合起来可以生成较复杂的表达式。

4.1 基础

4.1.1 基本概念

组合运算符和运算对象 :对于含有多个运算符的复杂表达式来说,要理解运算符的优先级、结合律以及运算对象的求值顺序。
运算对象转换 :在表达式求值的过程中,运算对象常常由一种类型转换成另外一种类型。
重载运算符 :当运算符作用于类类型的运算对象时,用户可自定义其含义,即为已存在的运算符赋予了另外一层含义。
左值和右值:C++的表达式要不然是左值,要不然是右值。在C语言中,左值可以位于赋值语句的左侧,而右值不能,在C++中二者的区别没这么简单。当一个对象被用作右值的时候,用的是对象的值(内容),当对象被用作左值的时候,用的是对象的身份(在内存中的位置)。
不同的运算符对运算对象的要求各不相同,有的需要左值运算对象,有的需要右值运算对象;返回值也有差异,有的得到左值结果,有的得到右值结果。一个重要的原则是在需要右值的地方可以用左值来代替,但是不能把右值当成左值使用。当一个左值被当成右值使用时,实际上使用的是它的内容。

使用关键字decltype的时候,左值和右值也有所不同。如果表达式的求值结果是左值,decltype作用于该表达式得到一个引用类型。

4.1.2 优先级和结合律

复合表达式是指含有两个或多个运算符的表达式。优先级和结合律决定了表达式中每个运算符对应的运算对象来着表达式的哪一部分。优先级规定了运算对象的组合方式,高优先级运算符的运算对象要比低优先级运算符的运算对象更加紧密地结合在一起,优先级相同的,从左往右的顺序组合运算对象。括号无视优先级和结合律。

4.1.3 求值顺序

有4种运算符明确规定了运算对象的求值顺序:逻辑与(&&)运算符,先求左侧运算对象的值,只有左侧对象的值为真时才能继续求右侧运算对象的值;逻辑或(||)运算符、条件(?:)运算符和逗号(,)运算符。
运算对象的求值顺序与优先级和结合律无关。
对于那些没有指定执行顺序的运算符来说,如果表达式指向并修改了同一个对象,将会引起错误并产生未定义的行为。

如果改变了某个运算对象的值,在表达式的其他地方不要在使用这个运算对象。但一个例外为:当改变对象的子表达式本身就是另一个子表达式的运算对象时该规则无效。例如*++iter中,递增运算符改变iter的值,但iter的值又是解引用运算符的运算对象。

4.2 算术运算符

在这里插入图片描述
一元运算符的优先级最高,接下来是乘除,最低的是加减。
算术运算符都能作用于任意算术类型(布尔型,整型,字符,浮点型)以及任意能转换为算术类型的类型。
算术运算符的运算对象和求值结果都是右值。
一元正号运算符、加法运算符和减法运算符都能作用于指针。布尔值不应该参与运算,对大多数运算符来说,布尔类型的运算对象都被提升为int类型。
当计算结果超出该类型所能表示的范围时就会产生溢出。
整数相除的结果还是整数,如果商含有小数部分,向0取整,即直接弃除小数部分。
取余运算符(%)的运算对象必须是整数类型,而且m%(-n)等于m%n; (-m)%n等于-(m%n)。

4.3 逻辑和关系运算符

关系运算符作用于算术类型或指针类型,逻辑运算符作用于任何能转换成布尔值的类型,两者的返回值都是布尔类型,运算对象和求值结果都是右值。
在这里插入图片描述逻辑与运算符(&&)当且仅当两个运算对象都为真时结果为真,逻辑或运算符(||)只要两个运算对象的一个为真结果就为真。两者都是先求左侧运算对象的值再求右侧运算对象的值,当且仅当左侧运算对象无法确定表达式的结果时才会计算右侧运算对象的值,称为短路求值。
逻辑非运算符(!)将运算对象的值取反后返回。
如果想要检测一个算术对象或指针对象的真值,最直接的方法就是将其作为if语句的条件:
在这里插入图片描述

4.4 赋值运算符

赋值运算符的左侧运算对象必须是一个可修改的左值。
在这里插入图片描述
赋值运算的结果是它的左侧运算对象,并且是一个左值,结果的类型就是左侧运算对象的类型。
C++11 允许使用花括号括起来的初始值列表作为赋值语句的右侧运算对象。
赋值运算满足右结合律。对于多重赋值语句中的每一个对象,它的类型或者与右边对象的类型相同,或者可由右边对象的类型转换得到。

赋值运算优先级较低。
复合赋值运算符:对对象施加某种运算,然后把计算的结果再赋给该对象。唯一的区别是左侧运算对象的求值次数:使用复合运算符只求值一次,使用普通的运算符则求值两次。
在这里插入图片描述

4.5 递增和递减运算符

递增和递减运算符有两种形式:前置版本和后置版本。前置版本首先将运算对象加1(或减1),然后将改变后的对象作为求值结果;后置版本也会将运算对象加1(或减1),但是求值结果是运算对象改变之前的那个值的副本。除非必须,否则不用后置版本。
在这里插入图片描述
在一条语句中混用解引用和递增运算符
如果我们想在一条复合表达式中既将变量加1或减1,又能使用它原来的值,这是可以使用后置版本。
在这里插入图片描述
在这里插入图片描述
如果一条子表达式该变了某个运算对象的值,另一条子表达式又要使用该值的话,运算对象的求值顺序就很关键了。因为递增和递减运算符会改变运算对象的值,所以要提防在复合表达式中错用这两个运算符。

4.6 成员访问运算符

点运算符和箭头运算符都可以用于访问变量,点运算符获取类对象的一个成员,ptr->mem等价于(*ptr).mem,因为解引用运算符的优先级低于点运算符,括号必须有。
在这里插入图片描述
箭头运算符作用于一个指针类型的运算对象,结果是一个左值。点运算符分两种情况:如果成员所属的对象是左值,那么结果是左值;反之,如果成员所属的对象是右值,那么结果为右值。

4.7 条件运算符

条件运算符(?:)允许我们把简单的if-else逻辑嵌入单个表达式中,使用形式为:
cond?expr1:expr2;
其中cond是判断条件的表达式,而expr1和expr2是两个类型相同或可能转化为某个公共类型的表达式。执行过程为:首先求cond的值,如果条件为真对expr1求值并返回该值,否则对expr2求值并返回该值。
当运算符的两个表达式都是左值或者都能转化为同一种左值类型时,运算的结果是左值,否则运算的结果是右值。
嵌套条件运算符
允许在条件运算符的内部嵌套另外一个条件运算符,即条件表达式可以作为另外一个条件运算符的cond或expr。
条件运算符满足右结合律,意味着运算对象(一般)按照从右往左的顺序组合。
在这里插入图片描述
在输出表达式中使用条件运算符
条件运算符的优先级非常低,因此当一条长表达式中嵌套了条件运算子表达式,通常要在它两端加上括号。
在这里插入图片描述

发布了16 篇原创文章 · 获赞 11 · 访问量 645

猜你喜欢

转载自blog.csdn.net/qq_42820853/article/details/104492243
今日推荐