C++ 浅谈操作符的优先级和结合顺序

来源:互联网 发布:vb可以编写安卓软件 编辑:程序博客网 时间:2024/06/05 06:29

        还是看 Primer,看到一个表达式,误认为它是错误的,没想到测试正确了。想一想,原来是自己没有想清楚。

      

        题目:设 iter 为 容器 vector<string> 的一个迭代器,判断语句“ iter++->empty(); ” 是否非法。



思路一(错误):

        -> 操作符 的 优先级比 后缀 ++ 要高,那么先调用 -> 操作符,但因为前面的 ‘+’ 非指针,判断非法。


思路二(正确):

        的确是先调用 -> 操作符,但是它发现前面不是一个变量或字面量,而是 '+' ,故认定前面为一个表达式,由于 -> 操作符 是左结合的,因此先把表达式的结果算出来,然后再调用 -> 操作符。当且仅当前面表达式的结果是一个含有 empty() 成员函数的指针时,编译器才不会报错。

        进一步,-> 是左结合的,后缀 ++ 是右结合的。左结合的操作符会使用它左边的表达式作为自己的操作数,右结合的操作符会使用右边的表达式作为自己的操作数。在这个例子中, -> 的优先级比 后缀 ++ 高,率先执行。它发现,左边是一个表达式,然后就先算出表达式的值,作为自己的操作数。随后,就证明了这个语句是合法的。


对比以上两个思路,思路一忽略了操作符的结合顺序(associativity),只考虑了优先级(precedence)。而思路二则兼顾了两者。  得出结论:C++的优先级和结合顺序共同决定了表达式被 evaluate (求值) 的顺序



下面讲一讲有关结合顺序的例子:


例1:

条件操作符 "cond ? expr1 : expr2" 是右结合的,给个例子:


string finalGrade = (grade > 90) ? "high pass" : (grade < 60) ? "fail" : "pass"


在这个例子中,条件操作符表达式 (grade < 60) ? "fail" : "pass" 会作为左边的条件操作符表达式的 operand。所以编译器求值(evaluate)的顺序,应当和下面这条语句等价:

string finalGrade = (grade > 90) ? "high pass" : ((grade < 60) ? "fail" : "pass")


        然而,条件操作符是比较特殊的,虽然右结合,但是它却可以提前判断条件是否满足,从而选择是否 evaluate 右边的表达式。因为如果条件满足了,那根本就不需要去evaluate 右边的表达式了,也避免了无谓的操作。

        所以,条件操作符的右结合可以说是一个例外。但是对于其他的“不能预判”的右结合的操作符,还是要按正常右结合的顺序来 evaluate 的,也就是说还是要和打上括号后的表达式有一样的 evaluate 顺序。


例二:

cout 重载的 << 操作符是左结合的。所以下面两条语句的 evaluate 顺序是一样的。

cout << a << b;
(cout << a) << b;



最后,献上 Primer 里对应chapter的summary的一句话:

"Precedence determines how operators are grouped in a compound expression. Associativity determines how operators at the same precedence level are grouped."


References

[1] 《C++ Primer Fifth Edition》  Stanley B. Lippman, Josée Lajoie, Barbara E. Moo




0 0