const在C++中定义真正不可修改的常量,其位置决定修饰对象:const修饰左侧最近成分,指针场景下int const与const int语义截然不同。

const 修饰符在 C++ 中不是“只读变量”,而是定义真正不可修改的常量(编译期或运行期确定),用错位置会导致语义完全相反——尤其是指针场景,const int* p 和 int* const p 根本不是一回事。
const 放在 * 左边还是右边?看它紧挨着谁
核心规则:const 修饰它**左边最近的类型成分**;如果左边没东西,就修饰右边的。这是理解所有组合的基础。
-
const int* p等价于int const* p:const 修饰int→ 指针所指的 int 不可改,但指针本身可指向别处 -
int* const p = &x:const 修饰*(即指针本身)→ p 的地址不可改,但 *p 可以赋新值 -
const int* const p = &x:两个 const 各管各的 → 指针不能换、所指内容也不能改
为什么 char* p = "hello" 在现代 C++ 中会报错?
字符串字面量(如 "hello")类型是 const char[6],隐式转成 const char*。旧代码允许转成 char* 是历史遗留,C++11 起禁止,否则可能误写导致未定义行为。
- 正确写法:
const char* p = "hello"(推荐)或auto p = "hello"(自动推导为 const char*) - 若真需要可修改副本:
char p[] = "hello"(数组初始化,不涉及 const 转换) - 强行绕过(不推荐):
char* p = const_cast→ 写操作仍 UB("hello")
函数参数里 const 引用和 const 指针的实际意义
它们不只是“防手抖”,关键在于影响重载决议、模板推导和对象生命周期管理。
立即学习“C++免费学习笔记(深入)”;
-
void f(const std::string& s):避免拷贝,且接受临时对象(如f(std::string("tmp"))) -
void f(std::string& s):不能传临时对象,也不能传 const 对象 -
void g(const int* p):可接收int*或const int*,但无法通过 p 修改原值 - 注意:
const在参数声明中是顶层 cv-qualifier,不影响函数签名唯一性(void f(int*)和void f(const int*)不能重载)
const 成员函数:不只是“不改成员变量”
void foo() const 表示该函数承诺不修改 this 对象的**任何非 mutable 成员**,但它能调用其他 const 成员函数、能读取所有成员、也能返回内部 const 引用——更重要的是,它决定了能否被 const 对象调用。
- 非常量对象可以调用 const 和非 const 版本;const 对象只能调用 const 版本
- mutable 成员可在 const 函数中修改(常用于缓存、计数器等不影响逻辑状态的字段)
- 返回
*this的 const 成员函数,返回类型是const X&,链式调用时后续操作受限制(比如不能接非 const 函数)
最易忽略的一点:const 正确性不是编译器“提醒你”,而是类型系统强制约束。一旦接口把某个参数声明为 const T*,调用方传入的指针是否带 const 就参与了类型匹配;而成员函数的 const 限定直接决定对象能否调用它——这不是风格问题,是契约的一部分。









