在 C++ 開發中,二維陣列的初始化一直是初學者常見的困擾。由於標準 C++ 要求陣列維度必須為編譯期常數,因此無法直接使用變數來定義二維陣列大小,例如 int i=5, j=4; int a[i][j]; 這類代碼會導致編譯錯誤。為了解決此問題,本文介紹一種利用模板類結合 Proxy 模式實現動態二維陣列的方法。
C++ 的內建陣列在編譯階段就需確定記憶體佈局,因此維度必須是常數表達式。若需根據運行時變數決定大小,必須採用動態記憶體分配或封裝類別。
Array2D 與內部 Proxy 類 Array1D以下代碼展示一個通用的二維陣列模板類,支援任意類型元素,並透過 operator[] 返回一個代表行的 Proxy 物件,實現雙重下標存取 arr[i][j] 的語法糖:
- template <class T>
- class Array2D {
- private:
- T* pData; // 一維動態陣列儲存所有元素
- int dim1, dim2; // 兩個維度大小
- int dim1Index; // 輔助索引
- // Proxy 類別:代表單一行,提供第二維度的下標操作
- class Array1D {
- private:
- int length;
- T* start;
- public:
- Array1D(T* s, int len) : start(s), length(len) {}
- T& operator[](int index) {
- if (index >= length) throw std::out_of_range("第二維度索引越界");
- return *(start + index);
- }
- };
- public:
- Array2D(int d1, int d2) : dim1(d1), dim2(d2) {
- pData = new T[dim1 * dim2];
- }
- ~Array2D() { delete[] pData; }
- Array1D operator[](int index) {
- return Array1D(pData + index * dim2, dim2);
- }
- void print() {
- for (int i = 0; i < dim1; ++i) {
- for (int j = 0; j < dim2; ++j)
- std::cout << *(pData + i * dim2 + j) << ' ';
- std::cout << '\n';
- }
- }
- };
- int main() {
- int rows = 2, cols = 2;
- Array2D<int> test(rows, cols);
- test[0][0] = 1; test[0][1] = 2;
- test[1][0] = 3; test[1][1] = 4;
- test.print();
- return 0;
- }
Array1D 作為中介層,將二維下標轉換為一維記憶體偏移,實現直觀的 [] [] 語法。Array1D::operator[] 中加入範圍檢查,拋出異常保護記憶體安全。T,複用性強。雖然此範例出自《More Effective C++》用於示範 Proxy 模式,但現代 C++ 開發中更推薦使用 std::vector<std::vector<T>> 或 std::vector<T> 配合一維索引計算,或是 C++23 引入的 std::mdspan。若需高效能數值計算,可考慮 Eigen、Armadillo 等專業線性代數庫。
透過模板類與 Proxy 模式,我們成功繞過 C++ 靜態陣列的維度限制,實現了語法自然、類型安全的動態二維陣列。理解此設計有助於掌握 C++ 進階技巧,如運算子重載、Proxy 模式、模板元編程基礎等。