题目

编写程序,阐述 const 成员函数的作用契约(承诺不修改对象内部任何逻辑状态,修饰内部隐式指针为 const ThisClass* const this)。重点展示 mutable(可变的)关键字的核心应用场景:当一个成员变量纯属内部性能优化实现细节(如访问缓存结果 cacheResult、调试统计计数器 accessCount 或线程安全互斥锁 std::mutex)时,用 mutable 修饰使其即便在 const 成员函数中依然能够合法被修改。

输入格式:无需外部输入。

输出格式:输出 const 对象在调用 const 成员函数时 mutable 缓存与访问计数器的自增变化。

数据范围与约定:物理不可变性(Bitwise constness)与逻辑不可变性(Logical constness)。

思路与算法

1. 物理不可变 vs 逻辑不可变
C++ 编译期默认强制“物理不可变性”(类的每一个 bit 都不可更改)。但实际工程中常需要“逻辑不可变性”(对用户而言对象状态没变,但内部做了一个结果缓存或记录了调用频次),这正是 mutable 的诞生初衷。

2. 互斥锁的终极修饰符
若一个只读查询函数(如 double getBalance() const)需要加互斥锁保证并发安全,因为加锁 mtx.lock() 必须改变互斥锁内部状态,互斥锁成员必须声明为 mutable std::mutex mtx_;,否则无法在 const 函数中加锁!

3. 重载区分
类可以同时提供 const 与非 const 版本的成员函数重载,编译器依据调用者对象是否具备常量性精确匹配。

完整程序

#include <iostream>
#include <string>

class HeavyCalculator {
private:
    int baseValue_;
    // mutable 修饰:允许在 const 成员函数中就地修改内部实现缓存
    mutable int cachedResult_;
    mutable bool isCacheValid_;
    mutable int accessCounter_;

public:
    explicit HeavyCalculator(int base) 
        : baseValue_(base), cachedResult_(0), isCacheValid_(false), accessCounter_(0) {}

    // const 成员函数:承诺逻辑上不改变计算器基数 baseValue_
    int compute() const {
        ++accessCounter_; // 允许:修改 mutable 调试计数器

        if (!isCacheValid_) {
            std::cout << "  [耗时计算] 缓存未命中,执行深度数学推演...\n";
            cachedResult_ = baseValue_ * baseValue_ + 42; // 修改 mutable 缓存
            isCacheValid_ = true;
        } else {
            std::cout << "  [极速读取] 直接命中 mutable 预热缓存\n";
        }

        return cachedResult_;
    }

    int getAccessCount() const {
        return accessCounter_;
    }
};

int main() {
    // 实例化为一个纯 const 常量对象
    const HeavyCalculator calc(10);

    std::cout << "--- 1. 常量对象首次调用 compute() ---\n";
    int res1 = calc.compute();
    std::cout << "首次计算结果: " << res1 << "\n\n";

    std::cout << "--- 2. 常量对象二次调用 compute() ---\n";
    int res2 = calc.compute();
    std::cout << "二次计算结果: " << res2 << "\n\n";

    std::cout << "该 const 实例已被调用访问次数: " << calc.getAccessCount() << " 次\n";

    return 0;
}

运行示例

输出:

--- 1. 常量对象首次调用 compute() ---
  [耗时计算] 缓存未命中,执行深度数学推演...
首次计算结果: 142

--- 2. 常量对象二次调用 compute() ---
  [极速读取] 直接命中 mutable 预热缓存
二次计算结果: 142

该 const 实例已被调用访问次数: 2 次