operator[]必须是非静态成员函数,因需访问对象内部状态;应返回引用以支持赋值,并提供const版本;越界检查非强制但推荐用at()实现;多维访问需proxy对象,注意生命周期与校验分工。
![c++怎么重载中括号 c++ subscript operator[]重载示例【重载】](https://img.php.cn/upload/article/001/431/639/176939754789561.jpg)
operator[] 必须是非静态成员函数
因为 operator[] 需要访问对象的内部状态(比如数组指针、大小等),它只能作为类的非静态成员函数实现,不能是全局函数或静态成员。写成全局函数会编译报错:error: 'operator[]' must be a non-static member function。
常见错误是想“对称地”像 operator+ 那样写成友元或全局,但 C++ 语法强制要求它绑定到实例——毕竟 a[i] 的语义天然依赖于 a 的状态。
- 必须声明为
T& operator[](size_t i)或const T& operator[](size_t i) const - 返回引用(
T&)才能支持赋值,如v[0] = 42 - 通常需配套提供 const 版本,否则
const MyVec v; v[0]会编译失败
下标越界不自动抛异常,得自己检查
C++ 标准库(如 std::vector::operator[])不检查越界,这是性能考量;你自己重载时也默认不检查——如果忘了加判断,就容易读写非法内存,引发未定义行为(崩溃、数据错乱、静默损坏)。
要不要检查,取决于使用场景:
立即学习“C++免费学习笔记(深入)”;
- 追求极致性能且调用方可信(如内部算法库)→ 不检查,靠断言
assert(i - 面向外部用户或调试阶段 → 显式抛异常:
if (i >= size_) throw std::out_of_range("index " + std::to_string(i)); - 注意:不要在
const版本里用assert后直接 return,否则非 const 版本可能绕过检查
返回 proxy 对象才能支持 v[i][j] 多维语法
如果类表示二维容器(如矩阵),想让 mat[i][j] 工作,不能让 operator[] 直接返回 int* 或 std::vector——那样会暴露内部结构,且无法控制第二维访问逻辑。
正确做法是返回一个代理(proxy)对象,它自己也重载 operator[]:
class Matrix {
std::vector> data_;
public:
class RowProxy {
std::vector& row_;
public:
RowProxy(std::vector& r) : row_(r) {}
int& operator[](size_t j) { return row_[j]; }
const int& operator[](size_t j) const { return row_[j]; }
};
RowProxy operator[](size_t i) { return RowProxy(data_[i]); }
const RowProxy operator[](size_t i) const { return RowProxy(data_[i]); }
};
proxy 对象生命周期需谨慎:它持的是引用,不能返回局部 vector 的引用;若底层存储可能 realloc(如 push_back),proxy 可能悬空。
operator[] 和 at() 的分工要明确
标准实践是:让 operator[] 走快速路径(无检查或仅 debug 断言),把带边界检查的版本留给 at() 成员函数——这和 std::vector 保持一致,使用者一看就懂语义差异。
-
v[i]→ 假设调用方已校验,快;v.at(i)→ 安全,抛异常 - 别在
operator[]里做at()的事,否则失去性能优势 - 如果类本身不维护 size(比如包装 C 数组),
at()就更需要显式传入长度参数,避免误用
多维容器中 proxy 的 operator[] 也应遵循同样原则:只做索引转发,不重复校验;真正检查放在 at() 或 proxy 的构造里。









