微软的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]的引用,也就是得到了内存中存储数据的实际位置,最终赋值操作把数据注入正确的内存位置