当前位置: 首页 > 图文教程 > 开发语言 > VC++ > 深入分析MFC中的CArray类

VC++
在类VC的界面实现中加入目录树
软件换肤技术在 BCB 中的实现
利用非模窗口生成MDI介面
报表输出轻松搞定
Windows 中不规则窗体的编程实现
解说Win32的窗口子类化
使用测试优先方法开发用户界面
一个简单的登录对话框的实现
一个简单的日记本程序
从资源中加载皮肤
一个在RichEdit中添加表情图象的类
ActiveSkin 4.3 软件换肤在VC中的实现
一种另类“关于(About)”对话框的动态显示方法
对话框打印预览及打印
关于如何换肤、子类化的解决方案
制作 MSN、QQ 的消息提示窗口
如何对 BCGControlBarPro 进行换肤
定制个性化的对话框窗口类
改变窗口中的光标形状
更新MFC中的视图,跟踪.NET Framework中的事件

VC++ 中的 深入分析MFC中的CArray类


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-10-30   浏览: 103 ::
收藏到网摘: n/a

深入分析MFC中的CArray类
作者:湖北 董志勇

我们在使用vc进行比较复杂的编程时,经常需要用到复杂的数组结构,并希望能实现动态管理。由于C++并不支持动态数组,MFC提供了一个CArray类来实现动态数组的功能。有效的使用CArray类,可以提高程序的效率。
MFC提供了一套模板库,来实现一些比较常见的数据结构如Array,List,Map。CArray即为其中的一个,用来实现动态数组的功能。
CArray是从CObject派生,有两个模板参数,第一个参数就是CArray类数组元素的变量类型,后一个是函数调用时的参数类型。
我们有一个类 class Object,我们要定义一个Object的动态数组,那么我们可以用以下两种方法:

CArray<Object,Object> Var1;CArray<Object,Object&> Var2;
Var1与Var2哪一个的效率要高呢? Var2的效率要高。为什么呢?接下来我们对CArray的源代码做一个剖析就清楚了。
先了解一下CArray中的成员变量及作用。
TYPE* m_pData; // 数据保存地址的指针int m_nSize; // 用户当前定义的数组的大小int m_nMaxSize; // 当前实际分配的数组的大小int m_nGrowBy; // 分配内存时增长的元素个数
首先来看它的构造函数,对成员变量进行了初始化。
CArray<TYPE, ARG_TYPE>::CArray(){	m_pData = NULL;	m_nSize = m_nMaxSize = m_nGrowBy = 0;}
SetSize成员函数是用来为数组分配空间的,从这里着手,看CArray是如何对数据进行管理的。SetSize的函数定义如下:
void SetSize( int nNewSize, int nGrowBy = -1 );
nNewSize 指定数组的大小
nGrowBy 如果需要增加数组大小时增加的元素的个数。
对SetSize的代码,进行分析。(由于代码太长,只列出部分重要部分)
void CArray<TYPE, ARG_TYPE>::SetSize(int nNewSize, int nGrowBy){	if (nNewSize == 0)	{	// 第一种情况	// 当nNewSize为0时,需要将数组置为空,	// 如果数组本身即为空,则不需做任何处理	// 如果数组本身已含有数据,则需要清除数组元素	if (m_pData != NULL)	{	//DestructElements 函数实现了对数组元素析构函数的调用	//不能使用delete m_pData 因为我们必须要调用数组元素的析构函数		DestructElements<TYPE>(m_pData, m_nSize);	//现在才能释放内存	delete[] (BYTE*)m_pData;	m_pData = NULL;	}	m_nSize = m_nMaxSize = 0;	}	else if (m_pData == NULL)	{	// 第二种情况	// 当m_pData==NULL时还没有为数组分配内存	//首先我们要为数组分配内存,sizeof(TYPE)可以得到数组元素所需的字节数	//使用new 数组分配了内存。注意,没有调用构造函数	m_pData = (TYPE*) new BYTE[nNewSize * sizeof(TYPE)];	//下面的函数调用数组元素的构造函数		ConstructElements<TYPE>(m_pData, nNewSize);	//记录下当前数组元素的个数	m_nSize = m_nMaxSize = nNewSize;	}	else if (nNewSize <= m_nMaxSize)	{	// 第三种情况	// 这种情况需要分配的元素个数比已经实际已经分配的元素个数要少	if (nNewSize > m_nSize)	{	// 需要增加元素的情况	// 与第二种情况的处理过程,既然元素空间已经分配,	// 只要调用新增元素的构造函数就Ok		ConstructElements<TYPE>(&m_pData[m_nSize], nNewSize-m_nSize);	}	else if (m_nSize > nNewSize)	{	// 现在是元素减少的情况,我们是否要重新分配内存呢?	// No,这种做法不好,后面来讨论。	// 下面代码释放多余的元素,不是释放内存,只是调用析构函数		DestructElements<TYPE>(&m_pData[nNewSize], m_nSize-nNewSize);	}	m_nSize = nNewSize;	}	else	{	//这是最糟糕的情况,因为需要的元素大于m_nMaxSize,	// 意味着需要重新分配内存才能解决问题	// 计算需要分配的数组元素的个数	int nNewMax;	if (nNewSize < m_nMaxSize + nGrowBy)	nNewMax = m_nMaxSize + nGrowBy;	else	nNewMax = nNewSize;	// 重新分配一块内存	TYPE* pNewData = (TYPE*) new BYTE[nNewMax * sizeof(TYPE)];	//实现将已有的数据复制到新的的内存空间	memcpy(pNewData, m_pData, m_nSize * sizeof(TYPE));	// 对新增的元素调用构造函数		ConstructElements<TYPE>(&pNewData[m_nSize], nNewSize-m_nSize);	//释放内存	delete[] (BYTE*)m_pData;	//将数据保存	m_pData = pNewData;	m_nSize = nNewSize;	m_nMaxSize = nNewMax;	}}
注意上面代码中标注为粗体的代码,它们实现了对象的构造与析构。如果我们只为对象分配内存,却没有调用构造与析构函数,会不会有问题呢?
如果只是使用c++的基本数据类型,如果int,long,那的确不会有什么问题。如果使用的是一个类,比如