C++ Primer 学习笔记 第四章 表达式(二)
位运算符
移位运算符(又叫 IO运算符)满足左结合律
移位运算符的优先级不高不低,介于中间:比算术运算符的优先级低,但比关系运算符、赋值运算符和条件运算符的优先级高。因此,一次使用多个运算符时,有必要在适当的地方加上括号使其满足我们的要求。
sizeof运算符
sizeof
运算符返回一条表达式或一个类型名字所占的字节数。sizeof
运算符满足右结合律,其所得的值是一个size_t
类型的常量表达式。运算符的对象有两种形式:
sizeof (type)
sizeof expr
在第二种形式中,sizeof
返回的是表达式结果类型的大小,与众不同的一点是,sizeof
并不实际计算其运算对象的值。
sizeof
运算符的结果部分地依赖于其作用的类型:
- 对
char
或者类型为cha
r的表达式执行sizeof
运算,结果得1. - 对引用类型执行
sizeof
运算得到被引用对象所占空间的大小。 - 对指针执行
sizeof
运算得到指针本身所占空间的大小。 - 对解引用指针执行
sizeof
运算得到指针指向的对象所占空间的大小,指针不需要有效。 - 对数组执行
sizeof
运算得到整个数组所占空间的大小,等价于对数组中所有元素各执行一次sizeof
运算并将所得结果求和。注意:sizeof
运算不会把数组转换成指针来处理。 - 对
string
对象或vector
对象执行sizeof
运算只返回该类型固定部分的大小,不会计算对象中的元素占用了多少空间。
逗号运算符
逗号运算符含有两个运算对象,按照从左向右的顺序依次求值。
对于逗号运算符来说,首先对左侧表达式求值,然后将求值结果丢弃掉。逗号运算符真正的结果是右侧表达式的值。如果右侧运算对象是左值,那么最终求值结果也是左值。
逗号运算符经常用在for循环当中:
vector<int>::size_type cnt = ivec.size();
//将把size到1的值赋给ivec的元素
for( vector<int>::size_type ix = 0;
ix != ivec.size(); ++ix,--cnt )
ivec[ix] = cnt;
这个循环在for语句的表达式中递增ix
、递减cnt
,每次循环迭代ix
和cnt
相应改变 。只要ix
满足条件,我们就把当前元素设成cnt
的当前值。
类型转换
隐式转换(implicit conversion)
在下面这些情况下,编译器会自动地转换运算对象的类型:
- 在大多数表达式中,比int类型小得整数值首先提升为较大的整数类型。
- 在条件中,非布尔值转换成布尔类型。
- 初始化过程中,初始值转换成变量的类型;在赋值语句中,右侧运算对象转换成左侧运算对象的类型。
- 如果算术运算或关系运算的运算对象有多种类型,需要转换成同一种类型。
- 函数调用时也会发生类型转换。
算术转换
- 整型提升
- 无符号类型的运算对象
其他类型的隐式转换
- 数组转换成指针
- 转换成布尔类型
- 转换成常量
允许将指向非常量类型的指针转换成指向相应常量类型的指针,对于引用也是这样。
相反的转换并不存在,因为它试图删除底层const。 - 类类型定义的转换
例子:在条件部分读入istream
:
string s, t = "a value"; //字符串字面值转换成string类型
while(cin >> s) //while的条件部分把cin转换成布尔值
条件(cin >> s)
读入cin
的内容并将cin
的值作为其求值结果。条件部分本来需要一个布尔类型的值,但是这里实际检查的是istream
类型的值。幸好,IO
库定义了从istream
向布尔值转换的规则,根据这一规则,cin
自动地转换成布尔值。所得的布尔值到底是什么由输入流的状态决定,如果最后一次读入成功,转换得到的布尔值是true
;相反,如果最后一次读入不成功,转换得到的布尔值是false
。
显式转换
虽然有时不得不使用强制类型转换,但这种方法本质上是非常危险的。
命名的强制类型转换
一个命名的强制类型转换具有如下形式:
cast-name<type>(expression);
其中,type是转换的目标类型,expression是要转换的值。如果type是引用类型,则结果是左值。
cast-name指定了执行的是哪种转换。cast-name是static_cast
、dynamic_cast
、const_cast
和reinterpret_cast
中的一种。
dynamic_cast
支持运行时类型识别,将在第19章有详细的介绍。
static_cast
任何具有明确定义的类型转换,只要不包含底层const,都可以使用static_cast
。例如,通过将一个运算对象强制转换成double类型就能使表达式执行浮点数除法:
//进行强制类型转换以便执行浮点数除法
double slope = static_cast<double>(j) / i;
const_cast
const_cast
只能改变运算对象的底层const。
const char *pc;
char *p = const_cast<char*>(pc); //正确:但是通过p写值是未定义的行为
对于将常量对象转换成非常量的行为,我们一般称其为“去掉const性质(cast away the const)”。一旦我们去掉了某个对象的const性质,编译器就不在阻止我们对该对象进行写操作了。
建议:避免强制类型转换
强制类型转换干扰了正常的类型检查,因此,强烈建议程序员避免使用强制类型转换。
补充
- 左值(lvalue)
指那些求值结果为对象或函数的表达式。一个表示对象的非常量左值可以作为赋值运算符的左侧运算对象。 - 右值(rvalue)
指一种表达式,其结果是值而非值所在的位置。 - 重载运算符(overloaded operator)
针对某种运算符重新定义的适用于类类型的版本。