const成员函数声明需在函数右括号后加const,修饰this指针为const T*,承诺不修改非mutable成员;const是函数签名一部分,影响重载选择与const对象调用权限。

const 成员函数的声明语法
在成员函数声明末尾加 const 关键字,表示该函数承诺不修改当前对象的任何非 mutable 成员变量。它不是修饰返回值或参数,而是修饰隐式 this 指针——让 this 的类型从 T* 变为 const T*。
正确写法示例:
class Widget {
public:
int getValue() const; // ✅ 声明为 const 成员函数
void setValue(int v) const; // ✅ 语法合法,但通常语义不合理(见下一条)
private:
int data_;
mutable int cache_; // ⚠️ mutable 成员可在 const 函数中修改
};
-
const必须紧贴在函数声明的右括号之后、分号之前 - 定义在类外时,
const要同时出现在声明和定义中(否则链接失败) - 重载时,
const是函数签名的一部分:非 const 对象会优先调用非 const 版本
为什么 const 成员函数里不能改成员变量
因为编译器会检查所有对非 mutable 成员的赋值、调用非 const 成员函数等操作,并报错:error: assignment of member 'Widget::data_' in read-only object。
常见触发场景:
立即学习“C++免费学习笔记(深入)”;
- 直接写
data_ = 42; - 调用另一个非
const成员函数,如updateCache(); - 返回成员变量的非常量引用,如
int& getRef() const { return data_; }(编译不过)
解决方法只有两个:去掉 const,或把目标成员声明为 mutable(仅适用于逻辑上“不影响对象对外表现”的缓存类字段)。
const 成员函数与 const 对象、const 引用的关系
只有 const 成员函数才能被 const 对象或 const 引用调用。普通对象可以调用 const 和非 const 版本,但编译器会按“精确匹配”优先选非 const 版本。
例如:
const Widget w1; Widget w2; w1.getValue(); // ✅ 只能调用 const 版本 w2.getValue(); // ✅ 调用 const 版本(如果只有 const 版),或非 const 版(如果有重载) // 若同时存在: // int getValue() const; // int getValue(); // 则 w2.getValue() 默认调用非 const 版
- 接口设计时,建议先写
const版本;若后续发现需要修改状态,再提供非const重载 - 返回值是否
const(如const int&)和成员函数是否const是两回事,别混淆 - 参数为
const T&不影响成员函数能否声明为const
容易忽略的坑:const 成员函数里调用 this->nonConstFunc()
这是最常被误判的错误——即使函数体看起来没改成员,只要内部调用了非 const 成员函数,整个函数就不能声明为 const。
比如:
class Buffer {
std::vector<char> buf_;
public:
size_t size() const { return buf_.size(); } // ✅ vector::size() 是 const 成员函数
void clear() const { buf_.clear(); } // ❌ 编译失败:vector::clear() 非 const
};
- 别凭直觉判断标准库函数是否 const,查文档或 IDE 提示(如
std::vector::at()是 const,operator[]有两个重载) - 自定义类型要确保其被调用的成员函数也标记了
const,否则链式调用会中断 - lambda 在 const 成员函数内默认不能捕获
this并修改成员(除非用mutablelambda,且不碰非 mutable 成员)
const 成员函数真正的边界在于“可观察状态不变”,而这个“可观察”由你定义的接口契约决定——编译器只管语法检查,不管语义是否合理。


















