C++语法相关

Posted by tianhaoo on March 16, 2022 本文阅读量

NULL/nullptr/void*

  • NULL不是个指针, 而是个宏定义的整数类型0, 用NULL无法传入接收对象类型参数的函数
  • nullptr是nullptr_t类型的对象, 可以转化为任何类型的指针
  • void*是一种特殊的指针类型(无类型指针), 可用于存放任意对象的地址, void指针只有强制类型转换后才可以正常对其操作

初始化列表

  • C++规定,对象的成员变量的初始化动作发生在进入构造函数本体之前
  • 若没有提供显示初始化列表,则编译器隐式使用成员类型的默认构造函数,若类没有默认构造函数,则编译器尝试使用默认构造函数将会失败
  • 如果类里面有用户定义类型成员, 那么不用初始化列表会有额外的性能开销
  • 必须使用初始化列表的情况:
    1. 初始化const修饰的类成员
    2. 需要初始化引用成员数据
    3. 需要初始化的数据成员是对象, 而且没有无参构造函数的情况

traits

  • 用在STL里面, 返回值的类型未知时, 可以萃取出元素类型
  • 配合模板的偏特化, 内置类型(没有value_type成员的类型), 也可以使用
  • 再特化一个const T*的, 萃取出正确的T,而不是const T

explicit

  • 在C++类的实例化过程中,存在一种隐式转换,即可以用单个实参来调用的构造函数定义了从形参类型到该类类型的一个隐式转换
  • 隐式转换有可能带来意料之外的结果
  • 在类的构造函数前加上explicit关键字,可以防止这种隐式转换

volatile

  • volatile和const是相反的
  • volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,编译器对访问该变量的代码就不再进行优化

inline

  • 作用: 为了解决一些频繁调用的小函数大量消耗栈空间(栈内存)的问题
  • 使用限制: 只适合函数体内代码简单的使用,不能包含复杂的结构控制语句比如while, switch, 并且不能是递归函数
  • inline仅仅是一个对编译器的建议,所以最后能否真正内联,看编译器的意思
  • 定义在类中的成员函数默认都是内联的
  • 坏处: 节省调用函数的开销, 但是额外复制了代码, 增大了代码区重复代码的体积

类型转换

  1. 隐式类型转换

    1. 数值加减乘除, 向上转换, 自动转换到位数多的类型
    2. 指针和void*的转换
    3. 构造函数只有一个值的实参转换(explicit关键字修饰构造函数可以防止隐式转换)
  2. 显式类型转换

    1. C风格的强制类型转换(不推荐)
    2. static_cast
    3. const_cast
    4. dynamic_cast
    5. reinterpret_cast

bind/placeholder

bind 这个东西是很鸡肋的,因为已经有了 lambda 表达式了,但是在 C++ 11 中 lambda 无法处理类型多态,bind可以;lambda 也不支持移动语义,bind 可以。