题目

编写程序,手写一个安全整型定长容器类 SafeArray。演示下标运算符 operator[] 的工业级双重载规范:必须成对提供非 const 版本 int& operator[](size_t index)(返回引用以支持作为左值被赋值修改)与 const 版本 const int& operator[](size_t index) const(保证常量对象只读访问);并通过越界防御断言或抛出 std::out_of_range 异常确保内存安全性。

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

输出格式:输出非 const 对象的就地赋值与 const 对象的安全只读访问日志。

数据范围与约定:下标运算符双版本重载、常量正确性(const correctness)。

思路与算法

1. 为什么必须成对重载
若只提供非 const 版本,当一个函数接收了 const SafeArray& arr 时,尝试 arr[0] 会直接遭遇编译报错;若只提供按值返回或 const 引用的版本,外部代码将无法执行 arr[0] = 100。因此必须根据常量性严格双重载。

2. 引用返回的重要性
左值版本必须返回真正的引用 T&,唯有返回引用,调用点才能被当作可寻址的左值接收赋值表达式。

3. 边界安全检查
原生 C 数组下标越界属于静默未定义行为;重载的下标运算符可在开发阶段植入越界断言检测,极大提升代码健壮性。

完整程序

#include <iostream>
#include <stdexcept>

class SafeArray {
private:
    int data_[5];
    size_t size_{5};

public:
    SafeArray() {
        for (size_t i = 0; i < size_; ++i) data_[i] = (i + 1) * 10;
    }

    // 1. 非常量版本:返回左值引用,允许读取与修改写入
    int& operator[](size_t index) {
        if (index >= size_) {
            throw std::out_of_range("非 const operator[] 访问下标越界!");
        }
        return data_[index];
    }

    // 2. 常量版本:返回 const 引用,只读保护
    const int& operator[](size_t index) const {
        if (index >= size_) {
            throw std::out_of_range("const operator[] 只读访问下标越界!");
        }
        return data_[index];
    }

    size_t size() const { return size_; }
};

// 接收常引用的只读展示函数
void printConstArray(const SafeArray& arr) {
    std::cout << "[只读函数] 遍历 const SafeArray: ";
    for (size_t i = 0; i < arr.size(); ++i) {
        std::cout << arr[i] << " "; // 自动命中 const operator[] 重载
    }
    std::cout << "\n";
}

int main() {
    SafeArray mutableArr;

    std::cout << "--- 1. 非 const 对象读写修改测试 ---\n";
    std::cout << "修改前 mutableArr[0] = " << mutableArr[0] << "\n";
    mutableArr[0] = 999; // 作为左值被修改
    mutableArr[4] = 888;
    std::cout << "修改后 mutableArr[0] = " << mutableArr[0] << "\n\n";

    std::cout << "--- 2. 常量对象只读调用测试 ---\n";
    const SafeArray constArr;
    printConstArray(constArr);

    std::cout << "\n--- 3. 越界异常拦截测试 ---\n";
    try {
        mutableArr[10] = 50; // 越界
    } catch (const std::out_of_range& e) {
        std::cout << "【安全防御】成功捕获越界异常: " << e.what() << "\n";
    }

    return 0;
}

运行示例

输出:

--- 1. 非 const 对象读写修改测试 ---
修改前 mutableArr[0] = 10
修改后 mutableArr[0] = 999

--- 2. 常量对象只读调用测试 ---
[只读函数] 遍历 const SafeArray: 10 20 30 40 50 

--- 3. 越界异常拦截测试 ---
【安全防御】成功捕获越界异常: 非 const operator[] 访问下标越界!