1. 基础
基本概念
左值和右值
- C++的表达式要不然是左值,要不然是右值
- 左值表达式的求值结果是一个对象或者一个函数,然而以常量对象为代表的某些左值实际上不能作为赋值语句的左侧运算对象。
- 有些表达式的求值结果是对象,但它们是右值而非左值。
- 左值:用的是对象的身份(在内存中的位置)
- 右值:用的是对象的值(内容)
- 使用关键字
decltype
时,左值右值会有所不同。
优先级与结合律
复合表达式:含有两个或多个运算符的表达式
运算符的优先级
2. 运算符
sizeof 运算符
- 返回一条表达式或者一个类型名字所占用的字节数
- 满足右结合律
- 返回值为
size_t
类型 sizeof
并不实际计算其运算对象的值
3. 类型转换
隐式转换
-
何时发生
比int类型小的整型值首次提升为较大的整型
非布尔值转换成布尔值
初始化过程中,初始值转换成变量的类型;赋值语句中,右侧对象转换为左侧运算对象的类型。
函数调用时也会发生类型转换(第六章)
算术转换
-
整型提升
小整数类型将转换为大整数类型
例如:
-
bool / char / short / unsigned short
的值存在int
中,它们的类型就会转换成int
-
较大的
char
类型提升成int/ unsigned int/ long/ unsigned long/ long long/ unsigned long long
中的最小的类型
-
-
无符号类型的运算对象
如果带符号类型和无符号类型在同一运算中,若带符号类型小于等于无符号类型,则带符号类型转换为无符号类型,否则依机器而定。
-
其他隐式类型转换
数组转换称指针
指针转换:
0/nullptr
可以转换为任意指针;- 指向任意非常量的指针可以转换为
void *
; - 指向任意对象的指针能转换成
const void*
转换为布尔类型
转换为常量:允许将指向非常量类型的指针转换称指向相应常量类型的指针
类类型定义的转换:编译器每次只能执行一种类类型定义的转换(7.5.4节)
显式转换
命名的强制类型转换
-
cast-name<type>(expression);
type为转换的目标类型,expression为转换的值
如果type为引用类型,则结果是左值
cast-name
-
static_cast
只要不包含底层const,都可以使用
把较大的运算类型转换给较小的运算类型时很有用(意味着不在乎精度损失)
对于编译器无法执行的类型转换也很有用
void *p = &d; double *dp = static_cat<double*>(p);
- 这时强制转换的结果与原始地址值相等
- 确保转换类型为所指类型,否则将产生未定义的后果
-
dynamic_cast
-
const_cast
只能改变运算对象的底层const
const char *pc; char *p = const_cast<char*>(pc); // 正确,但是通过p写值是未定义的行为
-
通过这个cast-name可以去掉const属性
-
如果对象本身不是常量,获得写权限是合法的,否则将产生未定义的后果
即pc指向对象为非常量,则是合法的(已验证)
pc指向对象为常量,编译器似乎也可以运行(???)
#include<iostream> using namespace std; int main(){ const char s[] = "test"; const char *pc = s; char *p = const_cast<char*>(pc); *p = 'x'; cout << s << endl; return 0; }
-
常用于带有函数重载的上下文钟
-
-
reinterpret_cast
为运算对象的位模式提供较低层次上的重新解释
例子:
int *ip; char *pc = reinterpret_cast<char *>(ip); string str(pc);
这样的行为将使编译器不会给出警告或者提示信息,用pc初始化str没有实际意义,甚至可能出错。
-
建议:避免使用强制类型转换
c风格的强制转换可能给程序引入无法察觉的错误
-