必须同时提供 const 和非 const 版本的 operator[]:非 const 版本返回 int& 支持读写,const 版本返回 const int& 仅支持读取;二者参数必须完全相同(单个 int),且必须为类的非静态成员函数,返回引用以保证语法正确性和性能。
![c++ 怎么重载下标运算符 [] 同时支持左值修改与右值只读访问](https://img.php.cn/upload/article/001/221/864/179333158956675.png)
必须同时提供 const 和非 const 版本的 operator[]
只写一个 int& operator[](int i) 能让 A[i] = 42 和 int x = A[i] 都通过编译,但一旦你传入 const Array& 就会编译失败。因为 const 对象只能调用 const 成员函数,而那个非 const 版本不满足条件。
常见错误现象:error: no viable overloaded '[]' 或 binding reference of type 'int &' to value of type 'const int' is not allowed,往往就卡在这一步。
- 非 const 版本返回
int&,支持读写(可出现在赋值左边) - const 版本返回
const int&,仅支持读取(防止意外修改) - 两个函数参数列表必须完全一致(都只有一个
int),否则编译器无法重载区分 - 不能只靠返回类型不同来重载——C++ 不允许仅靠返回类型区分重载函数
operator[] 必须是类的非静态成员函数
你不能把它写成全局函数或友元函数。语言强制要求:下标运算符必须定义为成员函数,因为 obj[i] 实际被翻译成 obj.operator[](i),只有成员函数能隐式访问 this 和私有成员(比如内部数组指针 m_p 或缓冲区 arr)。
如果尝试用友元写:int& operator[](MyArray& a, int i),编译器直接报错:overloaded 'operator[]' must be a member function。
立即学习“C++免费学习笔记(深入)”;
- 声明位置:必须在类定义内部(或类外定义但需加作用域,如
Array::operator[]) - 参数个数:严格限为一个(右操作数),左操作数由
this隐式提供 - 不能带默认参数,否则可能和内置数组行为冲突,引发二义性
返回引用是关键,不是值也不是指针
返回 int 值会导致 A[i] = 42 编译失败,因为临时量不能作为左值;返回 int* 虽然能解引用赋值,但破坏了 [] 的自然语义(用户不该手动写 *A[i])。
正确做法是返回元素的引用:int& 或 const int&。这样既保持了语法一致性,又避免了拷贝开销。
- 返回引用意味着你返回的是原存储位置的别名,不是副本
- 若内部用
std::vector或动态分配内存,确保索引有效后再取地址(比如先做越界检查再return m_data[i]) - 切忌返回局部变量的引用,或已释放内存的引用(比如在析构后还被调用)
边界检查要小心处理异常路径
标准库容器(如 std::vector::at())抛异常,但 operator[] 通常不检查——这是有意为之的设计选择:性能优先。如果你自己加检查,得明确策略:
- 抛异常(
throw std::out_of_range("index")):适合调试阶段或对安全性要求高的场景 - 断言(
assert(i >= 0 && i ):发布版自动剔除,保留调试信息 - 静默截断或返回默认值(如示例中返回
arr[0]):容易掩盖 bug,不推荐 - 注意 const 版本也必须做同样检查,否则 const 对象反而绕过防护
最易被忽略的一点:越界逻辑必须在两个版本里完全一致,否则 const 和非 const 行为割裂,会埋下难以复现的逻辑差异。


















