参考资料:
- 《C++ Primer》第5版
- 《C++ Primer 习题集》第5版
4.6 成员访问运算符(P133)
点运算符和箭头运算符都可用于访问成员,ptr->mem 等价于 (*ptr).mem 。箭头作用于指针类型对象,结果为左值;点运算符作用域对象,如果对象为左值则结果为左值,否则为右值。
4.7 条件运算符(P134)
条件运算符的形式如下:
cond ? expr1 : expr2;
其中,当 cond 为条件判断的表达式, expr1 和 expr2 是两个类型相同或可转换为某个公共类型的表达式。条件运算符首先对 cond 求值,若结果为真,则对 expr1 求值并返回该值;反之,则对 expr2 求值并返回该值。当两个表达式都是左值或能转换成同一种左值类型时,运算的结果为左值,否则为右值。
嵌套条件运算符
string finalgrade = (graph > 90) ? "high pass"
    							 : (grade < 60) ? "fail" : "pass";
条件运算符满足右结合律。
在输出表达式中使用条件运算符
条件运算符的优先级非常低,所以通常要在其两端加上括号。
4.8 位运算符(P135)

位运算符如何处理符号位依赖于机器,所以强烈建议将位运算符用于无符号类型。
移位运算符
移位运算符的右侧对象不能为负,且值必须严格小于结果的位数,否则将产生未定义行为。
需要注意的是,有符号类型在右移时插入符号位还是 0 由具体环境决定。
位求反运算符
位与、位或、位异或运算符
移位运算符满足左结合律
使用 cout 和 cin 进行 IO 操作时会用到重载的移位运算符,重载运算符的优先级和结合律不变。移位运算符的优先级比算术运算符低,比关系运算符、赋值运算符和条件运算符高。
4.9 sizeof运算符(P139)
 
sizeof 运算符满足右结合律,结果为 size_t 类型的常量表达式:
sizeof(type);
sizeof expr;
sizeof 可以返回表达式结果类型的大小,但不实际计算运算对象的值:
sizeof(*p);
sizeof Sales_data::revenue;
正是由于上述特性,即使 p 是一个无效指针,此处的解引用操作也不会有负面影响。C++11 新标准还允许通过作用域运算符来获取类成员的大小。
sizeof 运算符需要注意的情形:
- sizeof运算符作用于数组时,不会把数组转换成指针,而是返回整个数组所占空间的大小,等价于对数组中所有元素各执行一次- sizeof并求和。
- sizeof作用于- vector或- string对象时将将返回一个固定的值,这个值与对象所含的元素个数无关。
获取数组元素个数的常见写法:
sizeof(arr)/sizeof(*arr);
4.10 逗号运算符(P140)
逗号运算符含两个运算对象,从左向右依次求值。逗号运算符首先对左侧运算对象求值,然后将求值结果丢弃,再对右侧运算对象求值并将该值作为结果(如果右侧运算对象的结果为左值,那么逗号运算符的结果也为左值)。
4.11 类型转换(P141)
int ival = 3.14 + 3;
上述表达式发生了隐式转换。算术类型之间的隐式转换被设计得尽可能避免损失精度,所以整型一般会转换成浮点型。因此,上面的表达式中的 3 首先被转换成 double 型,然后再将浮点数加法的结果转换成 int 型。
何时发生隐式类型转换
- 在大多数表达式中,比 int小的整型值会提升为较大的整数类型。
- 条件中,非布尔值转换成布尔值
4.11.1 算术转换(P142)
算术转换的规则:运算对象转换成最宽的类型、整型转换成相应的浮点型。
整型提升
对 bool 、char 、short 等小整型,只要它们所有可能的值能存储在 int 里,就会被提升成 int ,否则被提升成 unsigned int 。
较大的 char 类型 (如 wchar_t )会被提升成最小能容纳其所有值的整型(至少为  int )。
无符号类型的运算对象
表达式首先执行整型提升,若提升后的运算对象均为带符号或均为无符号,则将小类型转换为大类型即可。
如果一个运算对象是无符号类型,一个对象是有符号类型,且那个无符号类型不小于有符号类型,则将带符号对象转换成无符号对象(如 int 和 unsigned int 运算,要将 int 转换成 unsigned int );如果带符号类型大于无符号类型,此时如果带符号类型能容纳无符号类型的所有值,则将无符号对象转换成有符号对象,否则将有符号对象转换成无符号类型(如 long 和 unsigned int ,转换的结果取决于 unsigned int 所占空间的大小)。
理解算术转换
3.14L + 'a';	// 'a'先被提升成int,再转换成long double
4.11.2 其他隐式类型转换(P143)
数组转换成指针:在大多数情况中,数组会自动转换成指向数组首元素的指针。当数组作为 decltype 关键字的参数,或 & 、sizeof 、typeid 等运算符的对象时,上述转换不会发生。
指针的转换:常量整数值 0 和字面量 nullptr 能转换成任意类型的指针;任意指向非常量的指针能转换成 void* ;任意指向对象的指针能转换成 const void* 。
转换成布尔类型:如果指针类型或算术类型的值为 0 ,则结果为 false ,否则为 true 。
转换成常量
类类型定义的转换:类类型能定义由编译器自动执行的转换。
4.11.3 显式转换(P144)
命名的强制类型转换
cast-name<type>(expression);
其中,type 是转换的目标类型,expression 是要转换的值,如果 type 是引用类型,则转换结果为左值。cast-name 是 static_cast 、dynamic_case 、const_cast 和 reinterpret_cast 中的一种
static_cast
 
任何具有明确定义,且不包含底层 const 的转换都可以使用 static_cast 。
int i = 1, j = 1;
double dval = static_cast<double>(j) / i;
当我们需要将大类型赋值给小类型而不计较精度损失时,使用 static_cast 可以避免编译器输出警告信息。
static_cast 常用于找回 void* 中的值:
double d = 3.14;
void *p = &d;
double *dp = static_cast<double*>(p);
const_cast
 
const_cast 只能改变对象的底层 const :
const char *pc = nullptr;
char *p = const_cast<char*>(pc);    // 正确
int *p = const_cast<int*>(pc);    // 错误
如果对象本身不是一个常量,使用 const_cast 获得写权限是合法的,否则将产生未定义行为:
int i = 1;
const int ci = 1;
const int *p1 = &i, *p2 = &ci;
int *q1 = const_cast<int*>(p1);    // 合法
int *q2 = const_cast<int*>(p2);    // 利用q2对ci进行写操作将会产生未定义行为
reinterpret_cast
 
reinterpret_cast 可以从位存储的角度对对象进行重新解释:
int *ip = nullptr;
char *pc = reinterpret_cast<char*>(ip);
应该尽可能避免使用强制类型转换
旧式的强制类型转换
早期的 C++ 版本中,显示强制类型转换包括以下两种类型:
type(expr);
(type)expr;
旧式的强制类型转换具有与 static_cast 、const_cast 和 reinterpret_cast 相似的行为。
4.12 运算符优先级表(P147)
 
 
 
                


![[C++基础]-多态](https://img-blog.csdnimg.cn/8daed871137246219ff7dfe3c58fb5a3.png)














