C++ Primer 笔记十四 表达式
表达式将运算符作用于一个或多个运算对象,每个表达式都有对应的求值结果。表达式本身也可以作为运算对象构成对多个运算符求值的复合表达式。
运算符
运算符 | 操作对象数量 |
---|---|
一元运算符 | 一个 |
二元运算符 | 两个,不要求类型相同,能转换成同类型即可 |
三元运算符 | 三个 |
函数调用 | 不限 |
重载运算符( overloaded operator and):对已存在的运算符重新定义适用于类类型的版本。需要注意的是,运算对象的个数、运算符的优先级和结合律,都是无法改变的;而运算对象的类型和返回值的类型是可以改变的。
左值和右值
左值 | 指求值结果为对象或函数的表达式 | 1. 当一个对象被用作右值的时候,用的是对象的值;当对象被用作左值的时候,用的是对象的身份(在内存中的位置)。 2. 在需要右值的地方可以用左值来代替,但是不能把右值当成左值使用。 |
右值 | 指求值结果为值而非值所在位置的表达式 |
decltype
作用于左值时,其结果将是一个引用类型。
优先级和结合律
- 高优先级运算符的运算对象较低优先级运算符的运算对象更为紧密地组合;
- 优先级相同情况下,组合规律由结合律确定;
- 括号无数优先级和结合律。
求值顺序
对于没有指定执行顺序的运算符来说,如果表达式指向并修改了同一个对象,将会引发错误并产生未定义的行为;下面的语句可以通过编译并运行产生结果,然而这样的代码是错误的:
// 错误代码示范:
int i = 0;
std::cout << i << ' ' << ++i << std::endl;
// g++ 4.8.4 编译运行结果为 1 1
四种明确规定运算对象求值顺序的运算符:
逻辑与(&&) | 先求左侧运算对象的值,该值为真时才对右侧运算对象求值。 |
逻辑或(||) | 先求左侧运算对象的值,该值为假时才对右侧运算对象求值 |
条件运算符(?:) | 先对条件求值,若条件为真,对表达式 1 求值并返回;否则,对表达式 2 求值并返回。 |
逗号运算符(,) | 首先对左侧运算对象求值,然后将求值结果丢弃,真正的结果是右侧表达式的值。 |
运算对象的求值顺序与优先级和结合率无关。
复杂表达式的处理建议:
- 拿不准的时候最好用括号来强制让表达式的组合关系符合程序逻辑的要求。
- 如果改变了某个运算对象的值,在表达式的其他地方不要再使用这个运算对象。
- 一个重要的例外:
*++iter;
// 递增运算符必须先求值,然后才轮到解引用运算