C++ 內建陣列下標訪問 arr[i] 不進行邊界檢查,越界訪問導致未定義行為,極難偵錯。重載 operator[] 可在類層面強制加入邊界檢查,構建安全陣列容器。
operator[] 必須作為成員函數重載,且通常提供兩個版本:
// 非常量版本:可讀可寫 Type& operator[](size_t index); // 常量版本:唯讀 const Type& operator[](size_t index) const;
關鍵差異:第二個版本以 const 修飾成員函數,允許在 const 物件上調用,且返回常量引用防止修改。
#include <iostream>
#include <string>
using namespace std;
class Array {
public:
Array() : m_length(0), m_pNums(nullptr) {}
Array(int n) : m_length(n) { m_pNums = new int[n]; }
~Array() { delete[] m_pNums; }
// 非常量版本:支援 arr[i] = val
int& operator[](int i) {
if (i < 0 || i >= m_length)
throw string("out of bounds");
return m_pNums[i];
}
// 常量版本:支援 const_arr[i] 唯讀
const int& operator[](int i) const {
if (i < 0 || i >= m_length)
throw string("out of bounds");
return m_pNums[i];
}
int getlength() const { return m_length; }
private:
int m_length;
int* m_pNums;
};
int main() {
Array A(5);
try {
// 寫入
for (int i = 0; i < A.getlength(); ++i)
A[i] = i;
// 讀取(含越界)
for (int i = 0; i < 6; ++i)
cout << A[i] << endl;
} catch (string s) {
cerr << s << ", i = " << 5 << endl;
}
}
0 1 2 3 4 out of bounds, i = 5
| 場景 | 調用版本 | 說明 |
|---|---|---|
Array a; a[0] = 1; | 非常量版 | 需修改元素,返回 int& |
const Array ca; int x = ca[0]; | 常量版 | 唯讀,返回 const int& |
void func(const Array& a) { a[0]; } | 常量版 | 函數參數為常量引用 |
若僅提供非常量版本,const 物件將無法使用下標訪問,嚴重限制實用性。
表達式 arr[5] 編譯器轉換為:
arr.operator[](5);
本例使用 throw string(...) 拋出異常,配合 try-catch 捕獲。現代 C++ 建議使用標準異常類別(如 std::out_of_range)替代裸字串。
assert 或宏關閉檢查operator[] 僅接受單一參數,多維陣列需返回代理物件或重載 operator()std::vector 提供 at() (檢查) 與 operator[] (不檢查) 兩種介面重載 operator[] 是構建安全容器的核心技術。雙版本重載(非常量/常量)確保語意正確與const 正確性,邊界檢查消除一大類難以發現的記憶體錯誤。掌握此模式,是理解 std::vector、std::array 等標準容器內部機制的關鍵一步。