const成员函数不能修改对象状态,但mutable修饰的成员变量除外;其this指针为const t*类型,仅允许修改mutable成员,且必须显式声明。

const 成员函数到底能不能改对象状态
不能,但有例外——mutable 修饰的成员变量除外。编译器只检查语法层面的修改:只要你在 const 成员函数里对非 mutable 成员赋值、调用非 const 成员函数、或通过 this 指针做非常量操作,就会报错,比如:error: assignment of member 'x' in read-only object。
常见错误现象是:想在 const 函数里缓存计算结果(比如懒加载哈希值),却忘了加 mutable,一写就编译不过。
-
const成员函数隐含this是const T*类型,所有成员访问都受此约束 - 只有
mutable成员可被修改,且必须显式声明(如mutable size_t cached_hash_;) - 不要用
const_cast强转this去绕过限制——这破坏接口契约,且可能引发未定义行为(尤其对象本身是真正 const 的时候)
什么时候必须写 const 成员函数
当你希望这个函数能被 const 对象、const 引用或 const 指针调用时,就必须加 const。否则连最基础的只读访问都会失败。
典型场景:容器遍历、日志打印、配置查询、哈希/比较逻辑(如 operator== 或 hash_value())。不加 const,下面代码直接报错:
立即学习“C++免费学习笔记(深入)”;
const MyString s = "hello"; s.length(); // 如果 length() 不是 const 成员函数,这里编译失败
- STL 容器(如
std::vector)的size()、empty()、at()都是const成员函数,否则无法在const容器上调用 - 重载
operator[]时,通常要提供两个版本:一个const版返回const T&,一个非常量版返回T& - 如果函数逻辑上不改变对象语义(比如只是格式化输出),但内部用了
mutable缓存,仍应声明为const—— 这是“逻辑 const”,也是标准做法
const 成员函数和 const 重载的参数匹配规则
编译器把 const 成员函数看作独立的重载候选,和对象的 const 性质严格匹配。不是“优先选 const 版”,而是“只选得上的那个”。
错误现象:给 const 对象调用了一个没加 const 的成员函数,报错 no matching member function,而不是“找不到合适重载”这种模糊提示。
- 同一个函数名,
void foo()和void foo() const是两个不同签名,互不覆盖 - 非 const 对象可以调用 const 或非 const 版;const 对象只能调用 const 版(哪怕非 const 版更“匹配”参数)
- 返回类型不影响重载决议,所以
T& get()和const T& get() const可共存,但int size()和size_t size() const不行(仅返回类型不同,非法重载)
const 成员函数里的 this 指针类型和指针安全
在 const 成员函数中,this 的类型是 const T* const:既不能改它指向的对象,也不能改它自己(即不能让 this 指向别处)。这是编译期强制的底层保障。
容易被忽略的一点:如果你在函数里返回了 this 或其成员地址,返回类型必须与 const 性质一致。否则会出现静默类型不匹配,或意外允许非常量修改。
- 返回
T*的函数不能在const成员函数里出现;应返回const T*或const T& - 返回成员引用时,注意
const传播:比如const std::string& name() const { return name_; },否则const对象调用后仍能修改name_ - 若函数返回智能指针(如
std::shared_ptr<t></t>),需谨慎——它包装的是非常量对象,const成员函数里返回它并不自动带来 const 安全性
const 接口设计真正的难点不在语法,而在于判断“什么算不改变对象状态”。比如修改引用计数、刷新时间戳、填充缓存——这些都该用 mutable,但得确保它们不破坏外部可见的逻辑一致性。稍不注意,const 就成了假的安全带。









