C 技巧:二維動態數組類模板

C++提供了許多強大的機制來實現代碼的高度復用、來使我們使用我們自已的類就像使用內置類型那樣方便快捷。比如模板,運算符重載等等。模板好比如是一個大批量生產函數和類的工廠,使我們不用再去關心與數據類型相關的繁瑣編程細節,把我們精力留給那些真正值得我們去認真思考的地方。而運算符重載則使我們的程序更直觀更簡潔,這不僅使我們更容易讀懂我們的程序,而且使我們能以一種更為流暢的方式來表達我們的想法。就像上篇文章說到的,如果我們把動態分配的二維數組用類模板實現,並重載相應的操作符,我們就能十分方便的使用我們自己定義的數組類型了。今天我正好把以往的程序整理了一下,就一併貼了出來,看下面的程序。下面的兩個類模板在vc++6.0上編譯運行良好,測試程序也都得到正確的結果,如果在其他編譯環境下有什麼問題,歡迎給我留言。

第一個頭文件Array.h是一維動態數組類模板:

//Array.h#ifndef CARL_SEN_ARRAY_H#define CARL_SEN_ARRAY_H

#include <iostream>#include <cstdarg>using std::out_of_range;using std::ostream;

template<typename T>class Array {protected: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);

//get,set成員函數unsigned int getSize() const {return size;}void setSize(unsigned int newSize);};

template <typename T>Array<T>::Array(unsigned int _size):data(new T[_size]), size(_size) {for(unsigned int i=0; i<size; ++i) {data[i]=T();}}

template <typename T>Array<T>::Array(unsigned int count, T data1, ...):size(count), data(new T[count]) {va_list ap;va_start(ap, count);for(unsigned int i=0; i<size; ++i) {data[i]=va_arg(ap, T);}va_end(ap);}

template <typename T>Array<T>::Array(const Array<T>& array):size(array.size), data(new T[array.size]) {for(unsigned int i=0; i<size; ++i) {data[i]=array.data[i];}}

template <typename T>Array<T>& Array<T>::operator=(const Array<T>& array) {if(&array!=this) {delete[] data;data=new T[array.size];size=array.size;for(unsigned int i=0; i<size; ++i) {data[i]=array.data[i];}}return *this;}

template <typename T>T& Array<T>::operator[](unsigned int index) {if(index>=size) {throw out_of_range("invalid index");}return data[index];}

template <typename T>const T& Array<T>::operator[](unsigned int index) const {if(index>=size) {throw out_of_range("invalid index");}return data[index];}

template <typename T>void Array<T>::setSize(unsigned int newSize) {T* const newData=new T[newSize];const unsigned int Min=size<newSize?size:newSize;for(unsigned int i=0; i<Min; ++i) {newData[i]=data[i];}delete[] data;data=newData;size=newSize;}

template <typename T>ostream& operator<<(ostream& os, const Array<T>& array) {for(int i=0; i<array.size; ++i) {os<<array.data[i]<<" ";}return os;}

#endif

第二個頭文件Array2D.h是二維動態數組類模板://Array2D.h#ifndef CARL_SEN_ARRAY2D_H#define CARL_SEN_ARRAY2D_H

#include "Array.h"#include <iostream>#include <cstdarg>using std::ostream;using std::out_of_range;

template <typename T>class Array2D {protected:unsigned int rows;unsigned int 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);

//計算第二維下標操作的嵌套類class RowArray {private:const Array2D<T>& array2D;unsigned int row;public:RowArray(Array2D<T>& _array2D, unsigned int _row=0):array2D(_array2D), row(_row) {}RowArray(const Array2D<T>& _array2D, unsigned int _row=0):array2D(_array2D), row(_row) {}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]; } }; friend class RowArray; //get,set函數 unsigned int getRows() const { return rows; } unsigned int getCols() const { return cols; } }; template <typename T> Array2D<T>::Array2D(unsigned int _rows, unsigned int _cols): rows(_rows), cols(_cols), array(_rows*_cols){ for(unsigned int i=0; i<rows*cols; ++i) { array[i]=T(); } } template <typename T> Array2D<T>::Array2D(unsigned int _rows, unsigned int _cols, T data1, ...): rows(_rows), cols(_cols),array(_rows*_cols){ va_list ap; va_start(ap, _cols); for(unsigned int i=0; i<rows*cols; ++i) { array[i]=va_arg(ap, T); } va_end(ap); } template <typename T> Array2D<T>::RowArray Array2D<T>::operator[](unsigned int row) { if(row>=rows) { throw out_of_range("invalid row"); } return RowArray(*this, row); } template <typename T> const Array2D<T>::RowArray Array2D<T>::operator[](unsigned int row) const { if(row>=rows) { throw out_of_range("invalid row"); } return RowArray(*this, row); } template <typename T> ostream& operator<<(ostream& os, const Array2D<T>& array2D) { unsigned int i, j; for(i=0; i<array2D.rows; ++i) { for(j=0; j<array2D.cols; ++j) { os<<array2D.array[i*array2D.cols+j]<<" "; } if(i!=array2D.rows-1) { os<<endl; } } return os; } #endif 現在就可以使用它們了,如下面的測試程序: #include "Array.h" #include "Array2D.h" #include <iostream> #include <string> using std::string; using std::cout; using std::endl; void testArray(); void testArray2D(); int main() { testArray(); testArray2D(); return EXIT_SUCCESS; } void testArray() { //普通數組 Array<int> a1(3); cout<<"Testing Array: print 1"<<endl; cout<<a1<<endl; //整體列印 unsigned int i; for(i=0; i<a1.getSize(); ++i) { a1[i]=i+1; //逐個賦值 } cout<<"Testing Array: print 2"<<endl; for(i=0; i<a1.getSize(); ++i) { cout<<a1[i]<<" "; //逐個列印 } cout<<endl; //常量數組 const Array<int> a2(3, 123, 234, 345); cout<<"Testing Array: print 3"<<endl; cout<<a2<<endl; cout<<"Testing Array: print 4"<<endl; for(i=0; i<a2.getSize(); ++i) { cout<<a2[i]<<" "; } cout<<endl; //拷貝構造 Array<int> a3(a1); cout<<"Testing Array: print 5"<<endl; cout<<a3<<endl; const Array<int> a4(a2); cout<<"Testing Array: print 6"<<endl; cout<<a4<<endl; //數組賦值給數組 Array<int> a5; a5=a4; cout<<"Testing Array: print 7"<<endl; cout<<a5<<endl; //增減數組元素 a5.setSize(a5.getSize()+1); a5[a5.getSize()-1]=111; cout<<"Testing Array: print 8"<<endl; cout<<a5<<endl; a5.setSize(a5.getSize()-2); cout<<"Testing Array: print 9"<<endl; cout<<a5<<endl; //保存對象 Array<string> a6(2, string("str0"), string("str1")); cout<<"Testing Array: print 10"<<endl; cout<<a6<<endl; for(i=0; i<a6.getSize(); ++i) { a6[i]+=static_cast<char>(48+i); } cout<<"Testing Array: print 11"<<endl; for(i=0; i<a6.getSize(); ++i) { cout<<a6[i]<<" "; } cout<<endl; const Array<string> a7(3, string("000"), string ("111"), string("222")); cout<<"Testing Array: print 12"<<endl; cout<<a7<<endl; for(i=0; i<a7.getSize(); ++i) { cout<<a7[i]<<" "; } cout<<endl; } void testArray2D() { //普通數組 Array2D<int> a1(2, 2); cout<<"Testing Array2D: print 1"<<endl;cout<<a1<<endl;unsigned int i,j;for(i=0; i<a1.getRows(); ++i) {for(j=0; j<a1.getCols(); ++j) {a1[i][j]=i+j;}}cout<<"Testing Array2D: print 2"<<endl;for(i=0; i<a1.getRows(); ++i) {for(j=0; j<a1.getCols(); ++j) {cout<<a1[i][j]<<" ";}cout<<endl;}

//常量數組const Array2D<int> a2(2, 2, 123, 234, 345, 456);cout<<"Testing Array2D: print 3"<<endl;cout<<a2<<endl;cout<<"Testing Array2D: print 4"<<endl;for(i=0; i<a2.getRows(); ++i) {for(j=0; j<a2.getCols(); ++j) {cout<<a2[i][j]<<" ";}cout<<endl;}//拷貝構造Array2D<int> a3(a1);cout<<"Testing Array2D: print 5"<<endl;cout<<a3<<endl;const Array2D<int> a4(a2);cout<<"Testing Array2D: print 6"<<endl;cout<<a4<<endl;

//數組賦值給數組Array2D<int> a5;a5=a4;cout<<"Testing Array2D: print 7"<<endl;cout<<a5<<endl;

//保存對象Array2D<string> a6(2, 2, string("str00"), string("str01"), string("str10"), string("str11"));cout<<"Testing Array2D: print 8"<<endl;cout<<a6<<endl;for(i=0; i<a6.getRows(); ++i) {for(j=0; j<a6.getCols(); ++j) {a6[i][j]+=static_cast<char>(48+i+j);}}cout<<"Testing Array2D: print 9"<<endl;for(i=0; i<a6.getRows(); ++i) {for(j=0; j<a6.getCols(); ++j) {cout<<a6[i][j]<<" ";}cout<<endl;}const Array2D<string> a7(2, 1, string("11111"), string("22222"));cout<<"Testing Array2D: print 10"<<endl;cout<<a7<<endl;cout<<"Testing Array2D: print 11"<<endl;for(i=0; i<a7.getRows(); ++i) {for(j=0; j<a7.getCols(); ++j) {cout<<a7[i][j]<<" ";}cout<<endl;}}

推薦閱讀:

Pandas Series用if判斷缺損值並修改,不影響原有空間
數組(一):基本原理
Excel工作表中數組常量的使用方法
《客映直播》資料04 吳廣儒老師辯證象數組方實踐課實錄
VBA數組和字典的經典用法及思路

TAG:技巧 | 動態 | 數組 | 模板 | 二維 |