Skip to content

Latest commit

 

History

History
85 lines (56 loc) · 4.03 KB

04. 表达式.md

File metadata and controls

85 lines (56 loc) · 4.03 KB

4. 表达式

4.1. 右值

C++ 的表达式要不然是右值 (rvalue), 要不然是左值 (lvalue). 这两个名词是从 C 语言继承过来的, 原本是为了帮助记忆: 左值可以位于赋值语句的左侧, 右值则不能.

当一个对象被用做右值的时候, 用的是对象的值 (内容); 当对象被用做左值的时候, 用的是对象的身份 (在内存中的位置).

4.2. ++i/i++

前置版本++i: 首先将运算对象加 1, 然后将改变后的对象作为求值结果.

后置版本i++: 也会将运算对象加 1, 但是求解结果是运算对象改变之前的那个值的副本.

以下摘录自 More Effective C++ Item 6:

// prefix form(++i): increment and fetch
UPInt&  UPInt::operator++()
{
    *this +=1;        // increment
    return *this;     // fetch
}
// postfix form(i++): fetch and increment
const UPInt UPInt::operator++(int)
{
    const UpInt oldValue = *this// fetch
    ++(*this);                    // increment
    return oldValue;             // return what was fetched
}

4.3. sizeof 运算符

4.3.1. 普通变量执行 sizeof

sizeof运算符的结果部分地依赖于其作用的类型:

  • 对 char 或者类型为 char 的表达式执行 sizeof 运算, 结果得 1.

  • 对引用类型执行 sizeof 运算得到被引用对象所占空间的大小.

  • 对指针执行 sizeof 运算得到指针本身所占空间的大小.

  • 对解引用指针执行 sizeof 运算得到指针指向的对象所占空间的大小.

  • 对数组执行 sizeof 运算得到整个数组所占空间的大小, 等价于对数组中所有元素各执行一次 sizeof 运算并将所得结果求和.

  • 对 string 对象或 vector 对象执行 sizeof 运算只返回该类型固定部分的大小.

4.3.2. 类执行 sizeof

class A {};
class B { B(); ~B() {} };
class C { C(); virtual ~C() {} };
class D { D(); ~D() {} int d; };
class E { E(); ~E() {} static int e; };
int main(int argc, char* argv[]) {
    std::cout << sizeof(A) << std::endl; // 输出结果为1
    std::cout << sizeof(B) << std::endl; // 输出结果为1
    std::cout << sizeof(C) << std::endl; // 输出结果为8,实例中有一个指向虚函数表的指针
    std::cout << sizeof(D) << std::endl; // 输出结果为4,int占4个字节
    std::cout << sizeof(E) << std::endl; // 输出结果为1,static不算
    return 0;
}
  • 定义一个空类型, 里面没有成员变量和成员函数, 求 sizeof 结果为 1. 空类型的实例中不包括任何信息, 本来求 sizeof 得到 0, 但是当我们声明该类型的实例的时候, 它必须在内存中占有一定的空间, 否则则无法使用这些实例, 至于占用多少内存, 由编译器决定, 一般有一个 char 类新的内存.

  • 如果在该类型中添加一个构造函数和析构函数, 再对该类型求 sizeof 结果仍为 1. 调用构造函数和析构函数只需要知道函数的地址即可, 而这些函数的类型只与类型相关, 而与类型的实例无关, 编译器也不会因为这两个函数在实例内添加任何额外的信息.

  • 如果把析构函数标记为虚函数, 就会为该类型生成虚函数表, 并在该类型的每一个实例中添加一个指向虚函数表的指针. 在 32 位的机器上, 一个指针占 4 字节的空间, 因此求 sizeof 得到 4; 在 64 位机器上, 一个指针占 8 字节的空间, 因此求 sizeof 得到 8.

4.4. 显式转换

  • static_cast: 任何具有明确定义的类型转换, 只要不包含底层 const, 都可以使用 static_cast.

  • dynamic_cast: 用于 (动态) 多态类型转换. 只能用于含有虚函数的类, 用于类层次间的向上向下转化.

  • const_cast: 去除 "指向常量的指针" 的 const 性质.

  • reinterpret_cast: 为运算对象的位模式提供较低层次的重新解释, 常用于函数指针的转换.