表达式由一个或多个运算符组成,对表达式求值将得到一个结果。
1. sizeof运算符
sizeof运算符返回一条表达式或一个类型名字所占的字节数,同一类型在不同机器上所占字节不一定相同。
1.1 字节对齐
1. 一层结构体
类型 | 字节段 | 类型 | 字节段 | |
---|---|---|---|---|
char | 0 | char | 0 | |
int | 4-7 | double | 8-15 | |
double | 8-15 | int | 16-19 | |
结构体 a | (0-15) -> 16 | 结构体 b | (0-19) -> 24 |
按结构体成员定义时的顺序计算字节大小,字节从0开始编号。字节对齐的方式是:
- 基本类型成员的起始地址从自己字节的整数倍开始。
- 基本类型成员 x 的字节数是 sizeof(x)。
- 字节总数是基本类型成员最大字节数的整数倍。
2. 二层结构体类型
类型 | 字节段 | 类型 | 字节段 | |
---|---|---|---|---|
char | 0 | char | 0 | |
short | 2-3 | a | 8-23 | |
a | 8-23 | short | 24-25 | |
结构体 x | (0-23) -> 24 | 结构体 y | (0-25) -> 32 |
二层结构体的字节对齐方式是:
- 基本类型成员的起始地址从自己字节的整数倍开始。内层结构体的起始地址从其最大基本类型成员字节的整数倍开始。
- 基本类型成员x的字节数是sizeof(x)。内层结构体成员y的字节数是sizeof(y)。
- 字节总数是内外层结构体内最大基本类型成员字节数的整数倍。
3. 数组类型的字节对齐
数组类型的字节对齐方式和结构体类型一样。
1.2 类的大小
和其它类型一样,类和它的对象的 sizeof 大小相等。
C++ 标准规定类的大小不为 0,空类的大小为 1 字节。这是因为类的实例必须在内存中占用一定的空间,否则无法使用这个实例。
函数成员和静态数据成员不占内存,因为它们与类的实例无关。但只要有虚函数就会有 1 个虚表指针,占 8 字节。
引用类型的成员和指针类型的成员一样占 8 字节。
2. 关系运算符
等号运算符==:
两个vector相比,比较的是它们的元素是否相等。
3. 显示转换
关键字 | static_cast | const_cast | reinterpret_cast | dynamic_cast |
---|---|---|---|---|
作用 | 任何具有明确定义的类型转换,只要不包括底层 const | 改变底层 const 操作对象必须是指针或引用类型 | 重新解释二进制数据 | 涉及派生的转换 |
例子 | 1.void指针与目标类型的指针互转 2.任意类型的表达式转换成void类型 3.基类与派生类对象的指针或引用互转 4.整型与浮点(舍去小数部分)、字符(ASCII码)、枚举互转 |
1. const_cast
以引用为例,指针同理。
const int& r1 = a;
int& r2 = const_cast<int&>(r1); // r1转r2,丢掉了const。r2也可以转r1。
只能转换指针或引用,即尖括号内必须是指针或引用。
修改r2的值:r1的值会被修改。a是变量则a的值会被修改,是常量则a的值不会被修改。
作用:int&可以隐式转换成const int&,而后者转前者需要显示转换。所以,r2可以匹配形参const int&,但r1不可匹配形参int&。如果想要r1匹配形参int&,就要先显式转换成r2。
2. static_cast
std::move 和 std::forward 就是利用 static_cast 实现的。
3. dynamic_cast
针static_cast中类层次的转换,提供一种安全的转换方式。
4. reinterpret_cast
转换前后二进制值相同,只是解释方式不同。