第04章_表达式

基础

  • 当一个对象被用作右值时,用的是对象的值(内容);当对象被用作左值时,用的是对象的身份(在内存中的位置)
  • 在需要右值的地方可以用左值来代替,但不能把右值当成左值使用

基本概念

优先级与结合律

求值顺序

算术运算符

逻辑和关系运算符

  • 进行比较运算时除非比较的对象是布尔类型,否则不要使用布尔字面值 true 和 false 作为运算对象

赋值运算符

  • 赋值运算符满足右结合率
    1
    2
    int i, j;
    i = j = 0; // 都被赋值为 0

递增和递减运算符号

  • 前置版本将对象本身作为左值返回;后置版本则将对象原始值的副本作为右值返回

成员访问运算符

  • 解引用运算符的优先级低于点运算符,所以执行解引用运算的子表达式两端必须加上括号

条件运算符

  • cond ? expr1 : expr2;

位运算符

  • 如果运算对象是小整型,则它的值会被自动提升成较大的整数类型
  • 尽量使用无符号数进行位运算

sizeof 运算符

  • 返回一条表达式或一个类型名字所占的字节数
  • sizeof 不会实际求运算对象的值
  • 对解引用指针执行 sizeof 得到指针指向的对象所占空间的大小,指针不虚有效
  • 对数组执行 sizeof 运算得到整个数组所占空间的大小

逗号运算符

  • 含有两个运算对象,按照从左向右的顺序依次求值
  • 首先对左侧的表达式求值,然后将求值结果丢弃掉,真正的结果是右侧表达式的值

类型转换

算术转换

  • 若运算对象要么都是带符号的、要么都不带符号,则小类型转换为大类型
  • 有一个有符号、一个无符号,且无符号类型不小于有符号类型,那么有符号类型转换为无符号的类型
  • 若有符号类型大于无符号类型,此时转换的结果依赖于机器。如果无符号类型的所有值都能存在该有符号类型中,则无符号类型的运算对象转换成有符号类型;如果不能,那么带符号类型的运算对象转换成无符号类型。

其他隐式类型转换

显式转换

static_cast

  • 任何具有明确定义的类型转换,只要不包含底层 const,都可以使用 static_cast
  • 把一个较大的算术类型赋值给较小的类型(避免编译器警告)
  • 对于编译器无法自动执行的类型转换也有用
    1
    2
    3
    4
    int i = 0;
    void *p = &i;
    // int *dp = p; // 不能自动转换,会报错
    int *dp = static_cast<int *>(p);

dynamic_cast

  • 支持运行时类型识别

const_cast

  • const_cast 只能改变运算对象的底层 const
    1
    2
    const char *pc;
    char *p = const_cast<char*>(pc); // yes, 但是通过 p 写值是为定义的行为
  • 如果一个类本身不是一个常量, 使用强制类型转换获得写权限是合法的行为; 然而如果对象是一个常量, 再使用 const_cast 执行写操作就会产生为定义的后果
  • 只有 const_cast 能改变表达式的常量属性, 使用其他形式的命名强制类型转换改变表达式的常量属性都将引发编译器错误

reinterpret_cast

  • 常用于为运算对象的位模式提供较低层次上的重新解释