基本概念
C++中运算符:
- 一元运算符,作用于一个运算对象的运算符,例如取地址符(&),解引用运算符(*)。
- 二元运算符,作用于两个运算对象的运算符,例如相等运算符(==),乘法运算符(*)。
- 三元运算符,作用于三个运算对象的运算符。
一些符号既能作为一元运算符也能作为二元运算符,例如*
。作一元运算符时表示解引用,作二元运算符时表示乘法运算。
对于含有多个运算符的复杂表达式来说,要想理解它的含义首先要理解运算符的优先级、结合律以及运算对象的求值顺序。
重载运算符
C++语言定义了运算符作用于内置类型和复合类型的运算对象时所执行的操作。当运算符作用于类类型的运算对象时,用户可以自定义其含义。这种自定义的过程事实上是为已存在的运算符赋予另外一层含义,所以称之为重载运算符。
对于重载运算符,其包括的运算对象的类型和返回类型都是由该运算符定义的,但是运算对象的个数,运算符的优先级以及结合律都是无法改变的。
左值和右值
C++的表达式要么是右值要么是左值,左值可以位于赋值语句的左侧,右值则不能。
当一个对象被用作右值的时候,用的是对象的值(内容);当对象被用作左值的时候,用的是对象的身份(在内存中的位置)。
- 赋值运算符需要一个非常量左值作为其左侧运算对象,得到的结果仍然是一个左值。
- 取地址符作用于一个左值运算对象,返回一个指向该运算对象的指针,这个指针是一个右值。
- 内置解引用运算符、下标运算符、迭代器解引用运算符的求值结果都是左值。
- 内置类型和迭代器的递增递减运算符作用于左值运算对象。
使用 decltype
的时候,左值和右值也有所不同。如果表达式的求值结果是左值,decltype
作用于该表达式(不是变量)得到一个引用类型。
假设p的类型是 int*
,因为解引用运算符生成左值,所以 decltype(*p)
的结果是 int&
,另一方面,因为取地址运算符生成右值,所以 decltype(&p)
的结果是 int**
,也就是说,结果是指向一个整型指针的指针。
优先级与结合律以及求值顺序
复合表达式是指含有两个或多个运算符的表达式。
括号无视普通的组合规则,表达式中括号括起来的部分被当作一个单元来求值,然后再与其它部分一起按照优先级组合。
对于没有指定执行顺序的运算符来说,如果表达式指向并修改了同一个对象,将会引发错误,并产生未定义的行为:
int i = 0;
cout<<i<<" "<<++i<<endl; //未定义的
对于上面的表达式,编译器可能先求 ++i
的值再求 i
的值,编译器也可能先求 i
的值再求++i
的值,所以表达式的行为是不可预知的。