const对象只能调用const成员函数,因编译器将this指针静态绑定为const classname* const,非const函数无法通过类型校验;mutable成员是唯一可在const函数中修改的例外。

const对象只能调用const成员函数,不能调用任何非const成员函数——这是编译器强制执行的规则,不是约定俗成。
const对象调用成员函数的编译期检查机制
编译器在解析 const Obj obj; 声明时,会将 obj 视为“逻辑上不可变”的实体。此时所有对它的成员函数调用,都会被限制在 const 成员函数签名范围内。这个检查发生在编译期,一旦越界(比如调用 setX() 这类明显可修改状态的函数),直接报错,不给运行机会。
关键点在于:this 指针类型被静态绑定为 const ClassName* const,而非 ClassName* const。这意味着哪怕函数体里没写任何修改语句,只要它没声明为 const,就无法通过 this 的类型校验。
- 错误示例:
const Date d(2024, 1, 1); d.SetMonth(2);→ 编译失败,SetMonth不是 const 成员函数 - 正确示例:
d.Print();→ 只要Print()声明为void Print() const,就能通过
非const对象可以混用两种成员函数
非const对象没有 this 权限收缩,所以既能调用 void func(),也能调用 void func() const。但要注意:这种“能调用”不等于“应该调用”。如果一个函数逻辑上只读(比如 size()、empty()),却没声明为 const,会导致 const 对象无法使用它,也违背接口设计一致性。
- 常见陷阱:
std::vector::begin()有两重载:非const版本返回iterator,const版本返回const_iterator。在 const 成员函数里访问vec.begin(),实际调用的是 const 版本——若你误以为它返回iterator并尝试解引用赋值,会编译失败 - 另一个坑:
operator[]通常有两个版本,const 版本必须返回const T&,否则 const 对象取值后无法用于只读上下文(比如传给接受const T&的函数)
mutable 成员是唯一例外
mutable 关键字允许某个成员变量在 const 成员函数中被修改,但它不会影响 const 对象的整体“只读承诺”。典型用途是缓存、引用计数、互斥锁等内部状态管理。
- 必须显式声明:
mutable std::mutex _mtx;或mutable bool _cached = false; - 不能滥用:
mutable int value;然后在 const 函数里改它,就破坏了 const 的语义,属于设计错误 - const 对象调用含
mutable修改的 const 成员函数,完全合法;但调用非const成员函数,哪怕只改了一个mutable成员,依然不被允许
最容易被忽略的是隐式调用链:比如你在 const 成员函数里调用了另一个类的非const成员函数(如 m_vec.push_back()),哪怕 m_vec 是类内 mutable 成员,也会失败——因为 push_back 本身不是 const 函数,而 m_vec 在当前 const 上下文中被视为 const 对象,只能调用其 const 成员函数。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











