第4章 表达式
4.1 基础
函数调用也是一种特殊的运算符
一些符号既能作为一元运算符,也能作为二元运算符,具体由上下文决定。
左值可以位于赋值语句的左侧,右值则不能。
当一个对象被用作右值的时候,用的时候对象的值(内容)
当对象被用作左值的时候,用的是对象的身份(在内存中的位置)
使用decltype的时候,如果表达式求值结果是左值,得到一个引用类型
假设p的类型是int*
decltype(*p)的结果是 int&
decltype(&p)的结果是 int**,即指向整型指针的指针
求值顺序
int i = f1() * f2(); //未规定先调用f1()还是f2()
int i = 0;
cout << i << " " << ++i << endl; //未定义的 不管哪种答案都是错误的
4.2 算术运算符
算术运算符的运算对象和求值结果都是右值
左结合律:优先级相同时按照从左到右
的顺序进行结合
%取余的运算对象必须是整数类型
C++11新标准规定商一律向0取整(即直接切除小数部分)
(-m)/n和m/(-n)都等于-(m/n)
m%(-n)等于m%n
(-m)%n等于-(m%n)
4.3 逻辑和关系运算符
关系运算符作用于算术类型或指针类型
,逻辑运算符作用于任意能转换成布尔值的类型。
逻辑运算符和关系运算符的返回值都是布尔类型
。
两类运算符的运算对象和求值结果都是右值
。
算术>关系>逻辑
逻辑运算符规定了运算对象求值的元素顺序
4.4 赋值运算符
赋值运算符的左侧运算对象必须是一个可修改的左值。
赋值运算满足右结合律
int ival, jval;
ival = jval = 0;
int ival, *pval;
ival = pval = 0; //错误,不能把指针的值赋给int
4.5 递增和递减运算符
int i = 0, j;
j = ++i; // j=1 i=1
j = i++; // j=1 i=2
两种运算符必须作用于左值运算对象。前置版本将对象本身作为左值返回,后置版本则将对象原始值的副本作为右值返回。
前置版本性能好
当前置和后置效果一样时,我们最好坚持用前置版本
auto pbeg = v.begin();
//输出元素直到遇到第一个负值为止
while(pbeg!=v.end() && *pbeg>=0){
cout << *pbeg++ << endl; //输出当前值并将pbeg向前移动一个元素
}
后置递增运算符优先级高于解引用运算符。*pbeg++
等价于*(peg++)
简洁是一种美德
方法一比方法二好,要习惯方法一的写法
//方法一
cout << *iter++ << endl;
//方法二
cout << *iter << endl;
++iter;
4.6 成员访问运算符
string s1 = "a string", *p = & s1;
auto n = s1.size();
n = (*p).size();
n = p->size();
n = *p.size(); //错误,解引用运算符优先级低于点运算符
4.7 条件运算符
cond ? expr1 : expr2
string finalgrade = (grade < 60) ? "fail" : "pass";
finalgrade = (grade > 90) ? "high pass"
: (grade < 60) ? "fail" : "pass";
条件运算符满足右结合律
嵌套影响代码可读性,做好别超过三层
4.8 位运算符
取反如下:
位与,位或,位异或运算符
注意逻辑或(||)与位或(|)的区别;逻辑与(&&)与位与(&)的区别。
4.9 sizeof运算符
满足右结合律,所得的值是size_t
类型
运算符的对象有两种形式
sizeof(type)
sizeof expr
sizeof *p
等价于sizeof(*p)
求arr数组的元素个数
constexpr size_t s2 = sizeof(arr)/sizeof(*arr);
int arr2[s2];
4.10 逗号运算符
规定了运算对象求值的顺序,从左到右
4.11 类型转换
隐式类型转换
int ival = 3.541 + 3; //隐式转换 int 3转换成double 3.0; ival为double 6.541 再转换成int 6
显式类型转换
cast-name<type>(expression);
cast-name
是static_cast、dynamic_cast、const_cast、reinterpret_cast
中的一种
static_cast,只要不包含底层const,static_cast非常有用
强制类型转换告诉读者和编译器,我们知道并不在乎潜在的精度损失。
double slope = static_cast<double>(j) / i;
const_cast,只能改变运算对象的底层const
const char *pc;
char *p = const_cast<char*>(pc);
旧式的强制类型转换:
type (expr); //函数形式的强制类型转换
(type) expr; //C语言风格的强制类型转换