跳转至

关键字

1 const

表示只读约束,用来限制变量、对象、指针、引用或成员函数的可修改性。
核心是看“谁不能被改”。

  • const T:对象本身不可修改
  • const T*:不能通过指针修改所指内容
  • T* const:指针本身不能改指向
  • const T&:常量引用,通常用于避免拷贝且防止修改
  • func() const:成员函数承诺不修改对象的非 mutable 成员

2 explicit

用于禁止构造函数或转换函数发生隐式转换。
核心作用是避免编译器“自动帮你转”。

  • 主要用于单参数构造函数,或可以等价看成单参数调用的构造函数
  • 加了 explicit 后只能显式构造,不能隐式赋值转换

3 inline

表示内联语义。
一方面是建议编译器在调用处展开函数,减少调用开销;另一方面更重要的是允许函数定义放在头文件中而不造成重复定义冲突。

  • 是否真的内联由编译器决定
  • 类内定义的成员函数通常天然带有内联语义
  • 适合短小、频繁调用的函数

4 new / malloc

两者都能申请内存,但层级不同。

new

new 是 C++ 运算符,用于创建对象。
除了分配内存,还会调用构造函数完成初始化。

malloc

malloc 是 C 标准库函数,只负责分配一块原始内存,不会调用构造函数。

核心区别

  • new/delete 面向对象生命周期
  • malloc/free 只做裸内存管理
  • new 失败默认抛异常,malloc 失败返回 nullptr
  • new[] 必须配对 delete[]
  • malloc 分配的内存必须用 free 释放,不能和 delete 混用

5 static

static 的核心不是“静态”两个字,而是改变存储期、作用域或归属方式。

修饰局部变量

生命周期变成整个程序运行期间,但作用域仍在函数内部。
只初始化一次。

修饰全局变量 / 全局函数

限制在当前源文件内可见,即内部链接。

修饰类成员变量

表示该成员属于类本身,而不是某个对象。
所有对象共享同一份静态成员变量。

修饰类成员函数

表示该函数属于类本身,没有 this 指针。
因此只能直接访问静态成员,不能直接访问非静态成员。


6 template

模板用于泛型编程,把类型参数化。
核心是“写一份代码,按类型生成不同实例”。

  • 函数模板:生成不同类型的函数
  • 类模板:生成不同类型的类
  • 模板实例化发生在编译期
  • 模板特化表示对某些特定类型提供特殊实现

通常模板定义写在头文件,因为实例化时编译器需要看到完整定义。


7 using / typedef

两者都用于定义类型别名,本质上是给已有类型起一个新名字。

typedef

传统写法,用旧语法声明别名。阅读时通常要从中间往两边看,可读性一般。

示例:typedef std::vector<int> IntVec;

using

现代写法,用等号形式定义别名。可读性更好,也更符合“左边是名字,右边是原类型”的直觉。

示例:using IntVec = std::vector<int>;

核心区别

大多数普通场景下,两者能力接近,都只是类型别名。
using 对模板别名支持更自然,所以现代 C++ 更推荐 using

补充

using 还有“引入名字”的作用,但这里主要记住它作为类型别名即可。


8 std::move / std::forward

std::move 本身不移动任何东西。
它只是把一个对象转换成右值引用,从而告诉编译器:这个对象可以被当作可移动对象处理。

  • 本质是类型转换,不是搬运内存
  • 是否真的发生移动,取决于目标类型是否支持移动语义
  • move 之后的对象仍然有效,但值通常不再保证
  • const 对象使用 std::move,通常也无法真正移动

std::forward 用于完美转发。
它会把参数按原本的值类别继续传递下去,而不是统一变成左值或右值。

  • 传进来是左值,转发后仍是左值
  • 传进来是右值,转发后仍是右值
  • 通常和模板参数 T&& 一起使用
  • 它和 std::move 的区别是:move 是强制转成右值,forward 是按原样转发