C++ 模板與運算符重載是實現泛型容器的利器。本文展示一套完整的一維/二維動態陣列類模板,支援任意型別、邊界檢查、拷貝語意、串流輸出與直觀的 arr[i][j] 存取語法。
Array<T>:一維動態陣列基礎類別Array2D<T>:二維陣列,內含 Array<T> 扁平化儲存,巢狀 RowArray 代理類別實現 [] 雙重下標Array<T> 關鍵特性operator[]:可變版本回傳 T&,const 版本回傳 const T&std::out_of_rangefriend operator<<setSize() 保留資料Array2D<T> 代理模式實現 arr[row][col]
// 巢狀代理類別
class RowArray {
private:
const Array2D<T>& array2D;
unsigned int row;
public:
RowArray(Array2D<T>& a, unsigned int r) : array2D(a), row(r) {}
RowArray(const Array2D<T>& a, unsigned int r) : array2D(a), row(r) {}
T& operator[](unsigned int col) {
if (col >= array2D.cols) throw out_of_range("invalid col");
return const_cast<Array2D<T>&>(array2D).array[row * array2D.cols + col];
}
const T& operator[](unsigned int col) const {
if (col >= array2D.cols) throw out_of_range("invalid col");
return array2D.array[row * array2D.cols + col];
}
};
// Array2D 雙重下標
RowArray operator[](unsigned int row) {
if (row >= rows) throw out_of_range("invalid row");
return RowArray(*this, row);
}
const RowArray operator[](unsigned int row) const {
if (row >= rows) throw out_of_range("invalid row");
return RowArray(*this, row);
}
關鍵點:RowArray 持有外層參考,透過 row * cols + col 計算扁平化索引,const_cast 處理可讀/可寫版本。
#ifndef CARL_SEN_ARRAY_H
#define CARL_SEN_ARRAY_H
#include <iostream>
#include <cstdarg>
#include <stdexcept>
using std::out_of_range;
using std::ostream;
template<typename T>
class Array {
unsigned int size;
T* data;
public:
Array(unsigned int _size = 0);
Array(unsigned int count, T data1, ...);
Array(const Array<T>& array);
Array& operator=(const Array<T>& array);
~Array() { delete[] data; }
T& operator[](unsigned int index);
const T& operator[](unsigned int index) const;
friend ostream& operator<<(ostream& os, const Array<T>& array);
unsigned int getSize() const { return size; }
void setSize(unsigned int newSize);
};
// ... 實現略 (見原始碼)
#endif
#ifndef CARL_SEN_ARRAY2D_H
#define CARL_SEN_ARRAY2D_H
#include "Array.h"
#include <iostream>
#include <cstdarg>
#include <stdexcept>
using std::ostream;
using std::out_of_range;
template <typename T>
class Array2D {
unsigned int rows, cols;
Array<T> array; // 扁平化儲存
public:
Array2D(unsigned int _rows = 0, unsigned int _cols = 0);
Array2D(unsigned int _rows, unsigned int _cols, T data1, ...);
class RowArray; // 前向宣告
RowArray operator[](unsigned int row);
const RowArray operator[](unsigned int row) const;
friend ostream& operator<<(ostream& os, const Array2D<T>& array2D);
unsigned int getRows() const { return rows; }
unsigned int getCols() const { return cols; }
class RowArray { /* ... 見上方 ... */ };
friend class RowArray;
};
// ... 實現略
#endif
#include "Array.h"
#include "Array2D.h"
#include <iostream>
#include <string>
void testArray() {
Array<int> a1(3);
a1[0]=1; a1[1]=2; a1[2]=3;
cout << a1 << endl; // 1 2 3
const Array<int> a2(3, 123, 234, 345); // 可變參數建構
Array<int> a3(a1); // 拷貝建構
Array<int> a5; a5 = a4; // 拷貝指派
a5.setSize(4); a5[3] = 111; // 動態擴充
Array<string> a6(2, string("str0"), string("str1")); // 非 POD 型別
}
| 原始做法 | 現代替代 | 優勢 |
|---|---|---|
可變參數 va_list | 可變參數模板 / std::initializer_list | 型別安全、編譯期檢查 |
手動 new[]/delete[] | std::vector<T> / std::unique_ptr<T[]> | RAII、例外安全 |
拋出 out_of_range | 可選:assert / std::optional / Contracts (C++26) | 效能/風格選擇 |
| 自定義串流輸出 | std::format (C++20) / ranges | 標準化格式化 |
此實現展示了模板、運算符重載、代理類別、記憶體管理等核心 C++ 技術的綜合運用。雖然現代 C++ 標準庫提供了 std::vector、std::array、std::mdspan (C++23) 等更完善的工具,但理解底層實現機制對於深度掌握 C++ 系統程式設計至關重要。