微軟的MFC架構中的CWordArray、CByteArray等一些類提供了一套用物件導向機制封裝的數組類,使用起來非常方便,相當於VB中的變長數組,而且由於完善的封裝,免去了用標準C++的new方法分配記憶體的操作,避免了因為忘記delete記憶體而造成記憶體流失的情況發生(前提是這些類的執行個體是在棧上建立,不是在堆上建立)。由於這些類重載了[]運算子,使得我們不必非要使用蹩腳的SetAt(),GetAt()來訪問數組元素,我們完全可以象使用普通數組一樣通過方括弧[]來訪問C**Array的元素。下段代碼簡要示範了這種使用方法:
CString s;
CWordArray cwarr;
cwarr.SetSize(1000);
cwarr[100]=90; //能夠這樣使用得益於[]運算子的重載。
s.Format("%d",cwarr[100]); //能夠這樣使用得益於[]運算子的重載。
AfxMessageBox(s);
在微軟的標頭檔afxcoll.h裡CWordArray定義裡可以看到如下聲明:
// overloaded operator helpers
WORD operator[](int nIndex) const;
WORD& operator[](int nIndex);
這便是運算子多載的申明。CWordArray的代碼是看不到的。但仿造CWordArray簡單的寫一個一維WORD數組類並實現[]運算子的重載並不難,代碼如下:
-------------------------------------------------------------------------------------
//一維WORD數組
class CWordArr
{
private:
WORD *m_pdat;
long m_size;
public:
CWordArr(long size)
{
m_pdat= new WORD[size];
m_size = size;
};
~CWordArr()
{
delete[] m_pdat;
};
WORD& operator[](long idx)
{
return m_pdat[idx];
}
};
-------------------------------------------------------------------------------------
運算子的重載可以看作是一個做了文法修飾的成員函數,可以看作是一種函數調用的方式,它提供了文法上的方便(參考自:《C++編程思想》一書)。cwarr[100]=90; 這一句代碼之所以能夠執行,就在於這句代碼其實調用了WORD& operator[](long idx)這個成員函數(姑且叫做成員函數吧),這個函數把m_pdat[idx]當作一個WORD型的引用返回了,就等於暫時給m_pdat[idx]申明了一個引用,所以賦值操作就等於給這個臨時的WORD型引用進行賦值,結果就是把90這個值注入了m_pdat[idx]這塊記憶體中,這句代碼執行完畢後,臨時的引用會被銷毀。這就是整個運算子多載的運行機理。
一維數組類的[]運算子多載並不難,最近為了最佳化一個演算法,自己寫了一個二維數組類,突發奇想,能不能重載[][]運算子呢,這樣就可以不用GetAt()SetAt()這些蹩腳的成員函數了。直到看了《C++編程思想》一書的運算子多載那一章,才發現自己對C++的瞭解還太不夠深入,想法比較幼稚,C++不會直接提供[][]的重載的,否則的話相當於重載一個三元運算子,C++裡還從未出現過任何三元運算子,三元運算子也沒有存在的意義,因為二元運算的疊加可以實現任意元的運算。同樣,所謂的[][]的重載,也必須通過兩次[]重載的疊加來實現。所以不可能在一個類裡面實現[][]的重載,必須有兩個類,一個是一維數組類,實現[]的重載,另一個類是二維數組類,必須持有一組一維數組類的執行個體,存放二維數組的各個行的數組,二維數組類也要重載[]運算子,這樣,通過兩次[]重載的疊加,就可以用a[x][y]的方式來訪問數組元素了。
代碼如下:
--------------------------------------------------------------------------------------
//一維WORD數組
class CWordArr
{
private:
WORD *m_pdat;
long m_size;
public:
CWordArr(long size)
{
m_pdat= new WORD[size];
m_size = size;
};
~CWordArr()
{
delete[] m_pdat;
};
WORD& operator[](long idx)
{
return m_pdat[idx];
}
};
//二維WORD數組
class C2DimWordArr
{
private:
CWordArr **m_p;//主指標
long m_row,m_column;//行數,列數。
public:
C2DimWordArr(long row,long column)
{
m_p=new CWordArr*[row];
for (long i=0;i<row;i++)
{
m_p[i]= new CWordArr(column);
}
m_row=row;
m_column=column;
}
~C2DimWordArr()
{
for (long i=0;i<m_row;i++)
{
delete m_p[i];
m_p[i]=NULL;
}
delete[] m_p;
}
CWordArr& operator[](long idx)
{
return *m_p[idx];
}
};
--------------------------------------------------------------------------------------
主調代碼如下,驗證類的正確性:
--------------------------------------------------------------------------------------
C2DimWordArr c2dwa(4,3);
long i,j;
for (i=0;i<4;i++)
for (j=0;j<3;j++)
c2dwa[i][j]= i*10 + j ;
CString s,stmp;
for (i=0;i<4;i++)
for (j=0;j<3;j++)
{
stmp.Format("[%d][%d] = %d /n", i,j,c2dwa[i][j]) ;
s+=stmp;
}
AfxMessageBox(s);
--------------------------------------------------------------------------------------
代碼的運行機理是這樣,當c2dwa[i][j]= i*10 + j ;這句代碼執行的時候,(c2dwa[i])先進行語義上的結合,執行了二維數組類的[]重載函數,得到了一個一維數組的引用,假設這個引用叫做b,接著b[j]進行結合,最終得到了m_pdat[idx]的引用,也就是得到了記憶體中儲存資料的實際位置,最終賦值操作把資料注入正確的記憶體位置。