const成员函数只能读取非mutable成员变量,可读可写mutable成员,指针/引用成员本身不可改但所指对象可修改。

const 成员函数能访问哪些成员变量
const 成员函数只能读取 this 指向的对象状态,不能修改任何非 mutable 的成员变量。编译器会把 this 当作 const T* const 类型处理,所以所有成员访问都受 const 限定。
常见错误现象:error: assignment of member 'x' in read-only object,通常是因为在 const 函数里写了 x = 5; 或调用了非 const 成员函数。
- 普通成员变量(如
int x;):可读,不可写 -
mutable成员(如mutable int cache_count;):可读可写,常用于缓存、日志计数等不改变逻辑状态的场景 - 指针成员(如
int* ptr;):指针本身不可改(ptr = nullptr;报错),但指针指向的内容仍可修改(*ptr = 42;合法) - 引用成员:同指针成员,引用本身不可重绑定,但所引对象若非常量,仍可修改
什么时候必须加 const 成员函数
当你需要通过 const 对象或 const 引用调用某个成员函数时,该函数必须声明为 const。否则编译失败,典型场景包括:
- 容器中存放
const T对象(如std::vector) - 函数参数是
const T&,却想调用t.get_value() - 返回值是
const T&,后续链式调用依赖 const 函数(比如obj.foo().bar()中foo()返回 const 引用,bar()就得是 const 成员)
示例错误:const Widget w; w.set_name("test"); —— 若 set_name 没有 const 修饰,直接报错;而 w.name() 若声明为 const std::string& name() const 才能通过。
const 和重载:如何避免二义性
const 成员函数和非 const 成员函数可以构成重载,编译器按调用对象的 const 性质自动选择。但要注意隐式转换和临时对象带来的陷阱。
- 对非 const 对象,优先匹配非 const 版本;对 const 对象或 const 引用,只考虑 const 版本
- 临时对象(如
Widget().get_data())被视为 const,因此必须有 const 版本才能调用 - 如果两个版本返回类型不同(如一个返回
int&,另一个返回const int&),注意不要让调用方误以为能修改临时对象的字段
典型写法:
int& value() { return data; } // 非 const 版本
const int& value() const { return data; } // const 版本,返回 const 引用防止越权修改
const 成员函数里调用其他成员函数的限制
const 成员函数内部只能调用其他 const 成员函数,不能调用非 const 版本,哪怕那个函数实际没修改状态——编译器只看声明,不看实现。
- 常见坑:自己写了
log_debug()这种“看起来只打日志”的函数,但忘了加const,结果在 const 函数里调用就报错 - 如果某个辅助函数确实不修改逻辑状态,但又需要被 const 函数调用,就必须把它也声明为 const
- 虚函数同样适用这条规则:基类 const 函数只能覆盖/重写为 const 虚函数;否则派生类无法多态调用
容易被忽略的一点:const 成员函数并不保证线程安全,也不阻止通过 const_cast 去 const(虽然那属于自找麻烦)。它只是编译期契约,提醒你“这里不该改状态”,别指望它拦住所有意外修改。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











