const成员函数必须加const后缀,否则无法在const对象上调用;内部不能调用非常量函数;返回引用或指针时需用const限定;只读成员应声明为const并在初始化列表中赋值。

const 成员函数必须加 const 后缀,否则无法在 const 对象上调用
这是最常被忽略的语法硬性要求。不加 const,哪怕函数体里一个成员都没改,编译器也认为它“可能修改对象”,从而拒绝在 const 对象或 const 引用上调用。
常见错误现象:
-
const MyClass obj; obj.getValue();报错:error: passing 'const MyClass' as 'this' argument discards qualifiers - 函数声明和定义不一致:头文件写了
int size() const;,实现时漏了const,链接期可能不报错但行为未定义
正确写法示例:
class DataContainer {
public:
int size() const { return m_data.size(); } // ✅ 必须带 const
double average() const { return m_sum / static_cast<double>(m_count); }
private:
std::vector<int> m_data;
int m_sum = 0;
int m_count = 0;
};</int></double>
const 成员函数内部不能调用非常量成员函数
编译器会逐层检查调用链。只要路径中任意一环是非 const 函数,整个调用在 const 上下文中就非法。
容易踩的坑:
- 看似只读的函数,内部调用了
validate(),而validate()是普通成员函数(比如它偷偷缓存了结果),就会编译失败 - 重载函数族中,
operator[]通常有两个版本:T& operator[](size_t)和const T& operator[](size_t) const;只实现前者,const对象取值会失败 - 使用
mutable成员可绕过限制,但仅限于真正不影响逻辑只读性的场景(如缓存、计数器)
示例修正:
class CacheWrapper {
public:
int get(int key) const {
hit_count++; // ❌ 错误:hit_count 是 mutable 才能这么写
return cache[key];
}
private:
mutable int hit_count = 0; // ✅ 允许在 const 函数中修改
std::map<int int> cache;
};</int>
返回值类型要配合 const 语义,避免隐式可写访问
返回 int 或 std::string 值没问题,但返回引用或指针时,类型必须是 const 限定的,否则调用者能通过返回值反向修改内部状态。
典型问题:
-
std::vector<int>& data() { return m_vec; }</int>—— 外部拿到非 const 引用,可任意修改m_vec - 正确做法是提供两组重载:
const std::vector<int>& data() const</int>和std::vector<int>& data()</int>,让 const 对象只能拿到只读视图 - 返回智能指针时同理:
std::shared_ptr<const node> getNode() const</const>
简短示意:
class Config {
public:
const std::string& name() const { return m_name; } // ✅ 返回 const 引用
std::string name() { return m_name; } // ✅ 非 const 版本返回值拷贝
private:
std::string m_name;
};
构造函数和析构函数不能是 const,但初始化列表是只读安全的关键
构造函数天生就是“写操作”,所以语法上禁止加 const;析构函数同理。但初始化列表决定了对象一旦构造完成,哪些成员就再也不能被修改 —— 这是只读类设计的起点。
实操要点:
- 所有真正需要只读的成员(如配置项、ID、尺寸)应声明为
const,并在构造函数初始化列表中赋值 - 不要把
std::vector、std::string等可变容器声明为const,除非你确定它全程只读且大小固定;否则用private+const成员函数封装访问 - 禁用拷贝赋值和移动赋值:
DataContainer& operator=(const DataContainer&) = delete;
只读类骨架示例:
class ImmutablePoint {
public:
ImmutablePoint(double x, double y) : m_x(x), m_y(y) {}
double x() const { return m_x; }
double y() const { return m_y; }
ImmutablePoint& operator=(const ImmutablePoint&) = delete;
private:
const double m_x;
const double m_y;
};
真正难的不是加 const,而是判断哪些函数该加、哪些数据该设为 const、哪些返回类型该加 const 限定——这取决于你对“只读”的定义粒度。有人只要求对象不可变,有人还要求内部缓存不污染语义,有人甚至要求线程安全的只读访问。每多一层约束,接口设计就得更谨慎一分。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











