在类的成员函数后面加const关键字,表示在成员函数中保证不会修改调用对象的成员变量。
注意:
1)mutable可以突破const的限制,被mutable修饰的成员变量,将永远处于可变的状态,在const修饰的函数中,mutable成员也可以被修改。
2)非const成员函数可以调用const成员函数和非const成员函数。
3)const成员函数不能调用非const成员函数。
4)非const对象可以调用const修饰的成员函数和非const修饰的成员函数。
5)const对象只能调用const修饰的成员函数,不能调用非cosnt修饰的成员函数。
这里出现了令人纠结的三个问题:
1、为什么要保护类的成员变量不被修改?
2、为什么用const保护了成员变量,还要再定义一个mutable关键字来突破const的封锁线?
3、到底有没有必要使用const和mutable这两个关键字?
保护类的成员变量不在成员函数中被修改,是为了保证模型的逻辑正确,通过用const关键字来避免在函数中错误的修改了类对象的状态。并且在所有使用该成员函数的地方都可以更准确的预测到使用该成员函数的带来的影响。而mutable则是为了能突破const的封锁线,让类的一些次要的或者是辅助性的成员变量随时可以被更改。没有使用const和mutable关键字当然没有错,const和mutable 关键字只是给了建模工具更多的设计约束和设计灵活性,而且程序员也可以把更多的逻辑检查问题交给编译器和建模工具去做,从而减轻程序员的负担。
示例:
#include <iostream>
class Counter {
public:
mutable int mutableCount;
int count;
Counter() : mutableCount(0), count(0) {}
// 常量成员函数,不允许修改除 mutable 成员之外的任何成员变量
void increment() const {
mutableCount++; // 允许修改因为它是 mutable 的
// count++; // 这行如果取消注释将导致编译错误,因为 count 不是 mutable 的
}
// 非常量成员函数,可以修改所有成员变量
void reset() {
mutableCount = 0;
count = 0;
}
void print() const {
std::cout << "Mutable Count: " << mutableCount << ", Count: " << count << std::endl;
}
};
int main() {
Counter myCounter;
myCounter.increment();
myCounter.print(); // 输出: Mutable Count: 1, Count: 0
myCounter.reset();
myCounter.print(); // 输出: Mutable Count: 0, Count: 0
return 0;
}
讨论三个问题:
-
为什么保护类的成员变量不被修改? 保护成员变量不被修改可以保证对象的状态不会被错误地改变,从而维护对象状态的一致性和预期行为。这对于多线程编程尤其重要,可以避免数据竞争和其他并发问题。
-
为什么用
const
保护了成员变量,还要再定义一个mutable
关键字来突破const
的封锁线? 在某些情况下,类的成员变量仅仅用于缓存或者统计等辅助功能,这些变量的修改并不影响对象的主要状态。mutable
允许这些辅助性成员变量在逻辑上保持可变,即使在常量成员函数中。 -
到底有没有必要使用
const
和mutable
这两个关键字? 使用const
和mutable
关键字可以提高程序的安全性、可读性和健壮性。它们帮助程序员明确对象的状态管理和函数行为,有助于错误预防和代码维护。当然,这也引入了额外的复杂性,但这通常是值得的,尤其是在大型项目中,明确状态和行为是非常关键的。