表达式
1 位运算符
位运算符作用域整数类型的运算算对象,并把运算对象看成是二进制位的集合。位运算符提供检查和设置二进制位的功能, 位运算符也可以使用在 bitset 类型
运算符 | 功能 | 用法 |
---|---|---|
~ | 按位求反 | ~expr |
<< | 左移 | expr1 << expr2 |
>> | 右移 | expr1 >> expr2 |
& | 位与 | expr & expr |
^ | 位异或 | expr ^ |
| | 位或 | expr | expr |
如果运算对象是 “小整形” ,则它的值会被自动提升成较大的整数类型。其运算对象可以是带符号的也可以是无符号的,具体如何处理运算对象的符号位依赖于机器。 | ||
注: 关于符号位如何处理没有明确的规定,所以建议仅将位运算符用于处理无符号类型。 |
移位运算符(又叫IO运算符)满足左结合律
2 sizeof 运算符
sizeof 运算符返回一条表达式或一个类型名字所占的字节数。 sizeof 运算符满足右结合律, 其所得的值是一个 size_t 类型的常量表达式。
sizeof不会实际求运算对象的值,因此即使对象是一个无效的指针也不会有什么影响,在 sizeof 的运算对象中解引用一个无效指针仍然说一种安全的行为,因为指针实际上并没有被真正使用。
sizeof运算符的结果部分地依赖于其作用的类型:
- 对char或者类型为char的表达式执行sizeof运算符,结果得1。
- 对引用类型执行sizeof运算得到被引用对象所占空间的大小。
- 对指针执行sizeof运算得到指针本身所占空间的大小。
- 对解引用指针执行sizeof运算得到指针指向的对象所占空间的大小,指针不需要有效。
- 对数组执行sizeof运算得到整个数组所占空间的大小,等价于对数组中所有的元素各执行一次sizeof运算并将所得结果求和。注意,sizeof 运算不会把数组转换成指针来处理。
- 对string对象或vector对象执行sizeof运算只返回该类型固定部分的大小,不会计算对象中的元素占用了多少空间。
3 类型转换
3.1 隐式转换
自动执行的类型转换,无须程序员的介入,有时甚至不需要程序员了解,这种转换类型被称作,隐式转换
算术类型之间的隐式转换被设计得尽可能避免损失精度。如,很多时候,如果表达式中既有整数型的运算对象又有浮点类型的运算对象,整数类型会转换成浮点型。
何时发生隐式转换
在下面这些情况下,编译器会自动地转换运算对象的类型:
- 在大多数表达式中,比int类型小的整型值首先提升为较大的整数类型。
- 在条件中,非布尔值转换成布尔类型。
- 初始化过程中,初始值转换成变量的类型;在赋值语句中,右侧运算对象转换成左侧运算对象的类型。
- 如果算术运算或关系运算的运算对象有多种类型,需要转换成同一种类型。
- 函数调用时也会发生类型转换。
3.2 算术转换
算术转换 的含义是把一种算术类型转换成另外一种算术类型。算术转换的规则定义了一套类型转换的层次,其中运算符的运算对象将转换成最宽的类型。
整型提升 负责把小整数类型转换成较大的整数类型。对于 bool、char、signed char、unsigned char、short 和 unsigned short 等类型来说,只要它们所有可能的值都能存在int里,他们就会提升从int类型;否则,提升成 unsigned int 类型。
3.3 显示转换
命名的强制类型转换
一个命名的强制类型转换具有如下形式:
cast-name<type>(expression);
其中,type 是转换的目标类型,expression是要转换的值。如果 type 是引用类型,则结果是 左值。 cast-name 是 static_cast 、dynamic_cast 、 const_cast 和 reinterpret_cast 中的一种。 dynamic_cast 支持运行时类型识别。
static_cast
定义: 通俗的说 static_cast 就是静态显式转换,用于基本的数据类型转换,及指针之间的转换,任何具有明确定义的类型转换,只要不包含底层const,都可以使用 static_cast。
int i,j;
double d = static_cast<double>(j) / i;
当需要把一个较大的算术类型赋值给较小的类型时,static_cast 非常有用。此时,强制类型转换告诉程序的读者和编译器: 我们知道并且不在乎潜在的精度损失。一般来说,如果编译器发现一个较大的算术类型试图赋值给较小的类型,就会给出警告;但是当我们执行了限制的类型转换后,警告信息就会被关闭。
使用:
- 用于类层次结构中基类和子类之间指针或引用的转换。进行上行转换(把子类的指针或引用转换成基类是表示)是安全的;子类的对象一般比基类大。这就是为什么基类指针可以指向并创建一个子类对象,但子类指针不能指向基类对象,即是因为上行转换是安全的,下行转换有风险。
- 进行下行转换(把基类指针或引用转换成子类指针或引用)时,由于没有动态类型检查,所以是不安全的。
- 用于基本数据类型之间的转换,如把 int 转换成 char,把 int 转换成 enum 等等,这种转换的安全性由开发人员来保证。
- 把 void 指针转换成目标类型的指针(不安全!),因为已经分配了内存,在更换目标类型的时候可能因为内存导致程序崩溃。
- 把任何类型的表达式转换成void类型。
dynamic_cast
定义: dynamic_cast 是用来执行继承体系中“安全的向下转型或跨系转型动作”,使用格式同 static_cast,在进行下行转换时可以得知转型是否成功,如果转失败的是指针,那么会以一个null指针形式表现出来,如果是引用那么会以一个expression 表现出来
dynamic_cast与static_cast区别:
static_cast 全部用于明确定义的变换,包括编译器允许我们所做的不用强制转换的安全变换和不太安全但清楚定义的变换,在进行类型间上行转换时,dynamic_cast 和 static_cast 的效果是一样的,在进行下行转换时比 static_cast 更安全
const_cast
定义: 对 “const” 和 “volatile” 进行转换,最常见的用途就是将某个对象的常量性去掉,使用其他类型转换表达式的 const 属性都将引发编译器编译错误。
const_cast 只能改变运算对象的底层 const。对于将常量对象转换成非常量对象的行为,我们一般称其为 “去掉 const 性质”。只有 const_cast 能改变表达式的常量属性,使用其他形式的强制类型转换将引发编译器错误。
注: const_cast 常用于有函数重载的上下文中。
const char *pc;
char *p = cosnt_cast<char *>(pc);
//这种转换不能改变表达式的类型const_cast 只能改变运算对象的底层const
reinterpret_cast
reinterpret_cast 通常为运算对象的位模式提供较低层次上的重新解释。例如:
int *ip;
char *pc = reinterpret_cast<char *>(ip);
reinterpret_cast 将对象转换为完全不同的意思。转换成的类型一般只能用于位操作,否则就是为其他隐秘的目的,这是所有转换中最危险的,且跟平台有密切关系。
强烈建议,避免使用强制类型转换。