const 的核心是声明“此处不允许修改”的编译期契约,违反即报错;它带类型、参与作用域与链接规则,修饰变量必须初始化,与宏有本质区别。

const 的核心作用不是“定义常量”,而是向编译器声明“此处不允许修改”——它是一条编译期契约,违反即报错,不产生运行时开销。
const 修饰变量必须初始化,且不能被赋值修改
这是最基础也最容易踩坑的点:声明 const int x 后不初始化,或后续写 x = 5,都会触发编译错误。它和 #define 的宏替换有本质区别——const 带类型、参与作用域和链接规则。
- 局部
const变量(如const double PI = 3.14159;)通常被编译器优化为立即数,不占栈空间 - 全局
const变量默认具有内部链接(static),其他文件看不到;想跨文件使用,必须写成extern const int GLOBAL_VAL = 42;并在头文件中声明extern const int GLOBAL_VAL; - 不要误以为
const int x = y;(y 是非常量)就等于“编译期常量”;只有字面量或 constexpr 表达式初始化的const才能当数组维度或模板参数用
const 和指针组合的三种写法,关键看 const 相对 * 的位置
口诀:const 离谁近,就修饰谁;更可靠的方式是“从右往左读”。容易混淆的不是语法,而是语义意图没想清。
-
const int* p→ 读作 “p 是指向 const int 的指针”:可改p(换地址),不可改*p(不能写*p = 10) -
int* const p = &x;→ 读作 “p 是 const 指针,指向 int”:必须初始化,不可改p(p = &y错),但可改*p -
const int* const p = &x;→ 两者都不可改,适合绑定到只读数据源并禁止重定向
函数参数加 const,本质是接口契约而非性能优化
写 void process(const std::string& s) 不是为了“避免拷贝”(那是引用的作用),而是明确告诉调用者和维护者:“这个函数绝不会修改 s 的内容”。编译器会强制执行这一点。
- 对值参(
void f(const int x))加 const 几乎无意义,因为 x 是副本,改不改都不影响实参 - 对指针参(
void f(const char* s))加 const,防止函数内写s[0] = 'A'导致越界或破坏只读字符串字面量(如传入"hello") - 对引用参加 const 是高频实践,既避免拷贝,又保证只读语义,比如
bool validate(const Config& cfg)
类成员函数末尾的 const,表示不修改 this 对象的任何成员
写 int size() const { return m_size; } 意味着该函数只能访问 const 成员变量、调用其他 const 成员函数,且 this 的类型隐式变为 const MyClass*。
- 非 const 对象可以调用 const 和非 const 版本;const 对象只能调用 const 版本
- 如果一个 const 成员函数里试图修改普通成员变量,编译器直接报错;哪怕只是调用了一个非 const 成员函数也不行
- 需要在 const 函数里修改某些缓存字段?得用
mutable显式标记那些字段,否则就是设计矛盾
真正难的不是记住语法,而是每次写 const 时都问一句:我是在声明“这里不能改”,还是在掩盖“其实应该改但我不想处理”?后者往往埋下 const_cast 的隐患,而那几乎总是错的。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











