CArray 类

注意

Microsoft基础类(MFC)库将继续受到支持。 但是,我们不再添加功能或更新文档。

支持类似于 C 数组的数组,但可以根据需要动态减小和增大。

语法

template <class TYPE, class ARG_TYPE = const TYPE&>
class CArray : public CObject

参数

TYPE
指定存储在数组中的对象类型的模板参数。 TYPE 是 CArray 返回的参数。

ARG_TYPE
模板参数,指定用于访问数组中存储的对象的参数类型。 通常是对 TYPE 的引用。 ARG_TYPE 是传递给 CArray 的参数。

成员

公共构造函数

名称 描述
CArray::CArray 构造一个空数组。

公共方法

名称 描述
CArray::Add 向数组的末尾添加一个元素;根据需要扩展该数组。
CArray::Append 将另一个数组追加到该数组中;根据需要扩展该数组
CArray::Copy 将另一个数组复制到该数组;根据需要扩展该数组。
CArray::ElementAt 在该数组中返回对元素指针的临时引用。
CArray::FreeExtra 若高于当前的上限,则将释放所有未使用的内存。
CArray::GetAt 返回给定索引位置处的值。
CArray::GetCount 获取此数组中的元素数。
CArray::GetData 允许访问该数组中的元素。 可以为 NULL。
CArray::GetSize 获取此数组中的元素数。
CArray::GetUpperBound 返回最大的有效索引。
CArray::InsertAt 在指定索引处插入一个元素(或另一个数组中的所有元素)。
CArray::IsEmpty 确定数组是否为空。
CArray::RemoveAll 从此数组中移除所有元素。
CArray::RemoveAt 移除特定索引处的元素。
CArray::SetAt 设置给定索引的值;不允许对该数组进行扩展。
CArray::SetAtGrow 设置给定索引的值;根据需要扩展该数组。
CArray::SetSize 设置要在该数组中包含的元素数。

公共运算符

名称 描述
operator[] 设置或获取位于指定索引处的元素。

备注

数组索引的起始位置始终为 0。 可以决定是修复上限,还是将数组设置为在添加超过当前上限的元素时进行扩展。 即使某些元素为 null,内存也会连续分配到上限。

注意

大多数重设 CArray 对象大小或向其添加元素的方法都使用 memcpy_s 来移动元素。 这是一个问题,因为 memcpy_s 与任何需要调用构造函数的对象都不兼容。 如果 CArray 中的项与 memcpy_s 不兼容,必须创建一个合适大小的新 CArray。 然后必须使用 CArray::Copy 和 CArray::SetAt 来填充新数组,因为这些方法使用赋值运算符而不是 memcpy_s。

与 C 数组一样,CArray 索引元素的访问时间是常数,并且与数组大小无关。

提示

在使用数组之前,先使用 SetSize 建立其大小并为其分配内存。 如果不使用 SetSize,则向数组添加元素会导致它经常重新分配和复制。 经常重新分配和复制会降低效率而且会产生内存碎片。

如果需要转储数组中的单个元素,则必须将 CDumpContext 对象的深度设置为等于或大于 1。

此类的某些成员函数调用全局帮助函数,这些函数必须针对 CArray 类的大多数用途进行自定义。 请参阅 MFC 宏和全局函数部分中的集合类帮助器主题。

数组类派生类似于列表派生。

有关如何使用 CArray 的详细信息,请参阅集合一文。

继承层次结构

CObject

CArray

要求

标头:afxtempl.h

CArray::Add

在数组末尾添加一个新元素,使数组增加 1。

INT_PTR Add(ARG_TYPE newElement);

参数

ARG_TYPE
指定此数组中引用元素的参数类型的模板参数。

newElement
要添加到此数组的元素。

返回值

所添加的元素的索引。

备注

如果已将 SetSize 与大于 1 的 nGrowBy 值一起使用,则可能会分配额外的内存。 但是,上限只会增加 1。

示例

// example for CArray::Add
CArray<CPoint, CPoint> ptArray;

CPoint pt(10, 20);
ptArray.Add(pt);             // Element 0
ptArray.Add(CPoint(30, 40)); // Element 1

CArray::Append

调用此成员函数可将一个数组的内容添加到另一个数组的末尾。

INT_PTR Append(const CArray& src);

参数

src
要追加到数组的元素的源。

返回值

第一个追加的元素的索引。

备注

数组必须是同一类型。

如有必要,Append 可能会分配额外的内存来容纳追加到数组的元素。

示例

CArray<CPoint, CPoint> myArray1, myArray2;

// Add elements to the second array.
myArray2.Add(CPoint(11, 22));
myArray2.Add(CPoint(12, 42));

// Add elements to the first array and also append the second array.
myArray1.Add(CPoint(1, 2));
myArray1.Append(myArray2);

CArray::CArray

构造一个空数组。

CArray();

备注

数组一次增长一个元素。

示例

CArray<CPoint, CPoint> ptArray;

CArray::Copy

使用此成员函数将一个数组的元素复制到另一个数组。

void Copy(const CArray& src);

参数

src
要复制到数组的元素的源。

备注

调用此成员函数以用另一个数组的元素覆盖一个数组的元素。

Copy 不释放内存;但是,如有必要,Copy 可能会分配额外的内存来容纳复制到数组的元素。

示例

CArray<CPoint, CPoint> myArray1, myArray2;

// Add elements to the second array.
myArray2.Add(CPoint(11, 22));
myArray2.Add(CPoint(12, 42));

// Copy the elements from the second array to the first.
myArray1.Copy(myArray2);

CArray::ElementAt

返回对数组中指定元素的临时引用。

TYPE& ElementAt(INT_PTR nIndex);
const TYPE& ElementAt(INT_PTR nIndex) const;

参数

nIndex
大于或等于 0 且小于或等于 GetUpperBound 返回的值的整数索引。

返回值

对数组元素的引用。

备注

它用于实现数组的左侧赋值运算符。

示例

请参阅 GetSize 的示例。

CArray::FreeExtra

释放在数组增长时分配的任何额外内存。

void FreeExtra();

备注

此函数对数组的大小或上限没有影响。

示例

请参阅 GetData 的示例。

CArray::GetAt

返回指定索引处的数组元素。

TYPE& GetAt(INT_PTR nIndex);
const TYPE& GetAt(INT_PTR nIndex) const;

参数

TYPE
指定数组元素类型的模板参数。

nIndex
大于或等于 0 且小于或等于 GetUpperBound 返回的值的整数索引。

返回值

当前位于此索引处的数组元素。

备注

传递负值或大于 GetUpperBound 返回值的值将导致断言失败。

示例

CArray<CPoint, CPoint> myArray;
CPoint pt;

// Add elements to the array.
for (int i = 0; i < 10; i++)
{
   myArray.Add(CPoint(i, 2 * i));
}

// Modify all the points in the array.
for (int i = 0; i <= myArray.GetUpperBound(); i++)
{
   pt = myArray.GetAt(i);
   pt.x = 0;
   myArray.SetAt(i, pt);
}

CArray::GetCount

返回数组元素的数目。

INT_PTR GetCount() const;

返回值

数组中的项数。

备注

调用此方法可检索数组中的元素数。 因为索引是从零开始的,所以大小比最大索引大 1。 调用此方法将生成与 CArray::GetSize 方法相同的结果。

示例

CArray<CPoint, CPoint> myArray;

// Add elements to the array.
for (int i = 0; i < 10; i++)
   myArray.Add(CPoint(i, 2 * i));

// Modify all the points in the array.
for (int i = 0; i < myArray.GetCount(); i++)
{
   CPoint &pt = myArray.ElementAt(i);
   pt.x = 0;
}

CArray::GetData

使用此成员函数可以直接访问数组中的元素。

const TYPE* GetData() const;
TYPE* GetData();

参数

TYPE
指定数组元素类型的模板参数。

返回值

指向数组元素的指针。

备注

如果没有可用的元素,GetData 将返回 null 值。

虽然直接访问数组元素可以帮助你更快地工作,但在调用 GetData 时要小心;你犯的任何错误都会直接影响数组的元素。

示例

CArray<CPoint, CPoint> myArray;

// Allocate memory for at least 32 elements.
myArray.SetSize(32, 128);

// Add elements to the array.
CPoint *pPt = (CPoint *)myArray.GetData();
for (int i = 0; i < 32; i++, pPt++)
{
   *pPt = CPoint(i, 2 * i);
}

// Only keep first 5 elements and free extra (unused) bytes.
myArray.SetSize(5, 128);
myArray.FreeExtra();

#if _DEBUG
afxDump.SetDepth(1);
afxDump << "myArray: " << &myArray << "\n";
#endif

CArray::GetSize

返回数组的大小。

INT_PTR GetSize() const;

备注

因为索引是从零开始的,所以大小比最大索引大 1。 调用此方法将生成与 CArray::GetCount 方法相同的结果。

示例

CArray<CPoint, CPoint> myArray;

// Add elements to the array.
for (int i = 0; i < 10; i++)
   myArray.Add(CPoint(i, 2 * i));

// Modify all the points in the array.
for (int i = 0; i < myArray.GetSize(); i++)
{
   CPoint &pt = myArray.ElementAt(i);
   pt.x = 0;
}

CArray::GetUpperBound

返回此数组的当前上限。

INT_PTR GetUpperBound() const;

备注

因为数组索引是从零开始的,所以此函数返回一个比 GetSize 小 1 的值。

条件 GetUpperBound( ) = -1 表示数组不包含任何元素。

示例

请参阅 CArray::GetAt 的示例。

CArray::InsertAt

InsertAt 的第一个版本在数组中的指定索引处插入一个元素(或元素的多个副本)。

void InsertAt(
    INT_PTR nIndex,
    ARG_TYPE newElement,
    INT_PTR nCount = 1);

void InsertAt(
    INT_PTR nStartIndex,
    CArray* pNewArray);

参数

nIndex
可能大于 GetUpperBound 返回的值的整数索引。

ARG_TYPE
指定此数组中元素类型的模板参数。

newElement
要放置在此数组中的元素。

nCount
应插入此元素的次数(默认为 1)。

nStartIndex
可能大于 GetUpperBound 返回的值的整数索引。

pNewArray
包含要添加到此数组的元素的另一个数组。

备注

在此过程中,它向上移动(通过递增索引)该索引处的现有元素,并将其上方的所有元素上移。

第二个版本插入另一个 CArray 集合中的所有元素,从 nStartIndex 位置开始。

相比之下,SetAt 函数替换一个指定的数组元素并且不移动任何元素。

示例

// example for CArray::InsertAt

CArray<CPoint, CPoint> ptArray;

ptArray.Add(CPoint(10, 20));         // Element 0
ptArray.Add(CPoint(30, 40));         // Element 1 (will become element 2)
ptArray.InsertAt(1, CPoint(50, 60)); // New element 1

CArray::IsEmpty

确定数组是否为空。

BOOL IsEmpty() const;

返回值

如果数组不包含任何元素,则为非零;否则为 0。

CArray::operator []

这些下标运算符是 SetAt 和 GetAt 函数的便捷替代项。

TYPE& operator[](int_ptr nindex);
const TYPE& operator[](int_ptr nindex) const;

参数

TYPE
指定此数组中元素类型的模板参数。

nIndex
要访问的元素的索引。

备注

第一个运算符,为不是 const 的数组调用,可用于赋值语句的右侧(右值)或左侧(左值)。 第二个运算符,为 const 数组调用,只能用于右侧。

库的调试版本断言下标(在赋值语句的左侧或右侧)是否超出范围。

示例

CArray<CPoint, CPoint> myArray;

// Add elements to the array.
for (int i = 0; i < 10; i++)
{
   myArray.Add(CPoint(i, 2 * i));
}

// Modify all the points in the array.
for (int i = 0; i <= myArray.GetUpperBound(); i++)
{
   myArray[i].x = 0;
}

CArray::RelocateElements

当数组应增大或收缩时,将数据重新定位到新缓冲区。

template<class TYPE, class ARG_TYPE>
AFX_INLINE void CArray<TYPE, ARG_TYPE>::RelocateElements(
    TYPE* pNewData,
    const TYPE* pData,
    INT_PTR nCount);

参数

pNewData
元素数组的新缓冲区。

pData
元素的旧数组。

nCount
旧数组中的元素数。

备注

pNewData 始终足以容纳所有 pData 元素。

CArray 实现使用此方法在数组应增大或收缩(调用 SetSize 或 FreeExtra)时将旧数据复制到新缓冲区。 默认实现只是复制数据。

对于其中一个元素包含指向其自身成员之一的指针或另一个结构包含指向其中一个数组元素的指针的数组,指针不会以纯副本形式更新。 在这种情况下,可以通过使用相关类型实现 RelocateElements 的专用化来更正指针。 你还负责数据复制。

CArray::RemoveAll

从此数组中移除所有元素。

void RemoveAll();

备注

即便数组已为空,该函数仍有效。

示例

CArray<CPoint, CPoint> myArray;

// Add elements to the array.
for (int i = 0; i < 10; i++)
   myArray.Add(CPoint(i, 2 * i));

myArray.RemoveAll();

#ifdef _DEBUG
afxDump.SetDepth(1);
afxDump << "myArray: " << &myArray << "\n";
#endif

CArray::RemoveAt

删除从数组中指定索引处开始的一个或多个元素。

void RemoveAt(
    INT_PTR nIndex,
    INT_PTR nCount = 1);

参数

nIndex
大于或等于 0 且小于或等于 GetUpperBound 返回的值的整数索引。

nCount
要移除的元素数。

备注

在此过程中,它会将已删除元素上方的所有元素向下移动。 它会递减数组的上限,但不释放内存。

如果尝试删除的元素多于删除点上方的数组中包含的元素,则库的调试版本会断言。

示例

CArray<CPoint, CPoint> myArray;

// Add elements to the array.
for (int i = 0; i < 10; i++)
{
   myArray.Add(CPoint(i, 2 * i));
}

myArray.RemoveAt(5);

#ifdef _DEBUG
afxDump.SetDepth(1);
afxDump << "myArray: " << &myArray << "\n";
#endif

CArray::SetAt

在指定索引处设置数组元素。

void SetAt(INT_PTR nIndex, ARG_TYPE newElement);

参数

nIndex
大于或等于 0 且小于或等于 GetUpperBound 返回的值的整数索引。

ARG_TYPE
指定用于引用数组元素的参数类型的模板参数。

newElement
要存储在指定位置的新元素值。

备注

SetAt 不会导致数组扩展。 如果希望数组自动扩展,请使用 SetAtGrow。

必须确保索引值代表数组中的有效位置。 如果超出范围,则库的调试版本会断言。

示例

请参阅 GetAt 的示例。

CArray::SetAtGrow

在指定索引处设置数组元素。

void SetAtGrow(INT_PTR nIndex, ARG_TYPE newElement);

参数

nIndex
大于或等于 0 的整数索引。

ARG_TYPE
指定此数组中元素类型的模板参数。

newElement
要添加到此数组的元素。 允许 NULL 值。

备注

如有必要,数组会自动扩展(即调整上限以适应新元素)。

示例

// example for CArray::SetAtGrow
CArray<CPoint, CPoint> ptArray;

ptArray.Add(CPoint(10, 20)); // Element 0
ptArray.Add(CPoint(30, 40)); // Element 1
// Element 2 deliberately skipped
ptArray.SetAtGrow(3, CPoint(50, 60)); // Element 3

CArray::SetSize

确定空数组或现有数组的大小;必要时分配内存。

void SetSize(
    INT_PTR nNewSize,
    INT_PTR nGrowBy = -1);

参数

nNewSize
新数组大小(元素数)。 必须大于或等于 0。

nGrowBy
需要增加大小时要分配的最小元素槽数。

备注

如果新大小小于旧大小,则会截断该数组,并释放所有未使用的内存。

在开始使用数组之前,使用此函数设置数组的大小。 如果不使用 SetSize,则向数组添加元素会导致它经常重新分配和复制。 经常重新分配和复制会降低效率而且会产生内存碎片。

nGrowBy 参数会在数组增长时影响内部内存分配。 它的使用绝不会影响 GetSize 和 GetUpperBound 报告的数组大小。 如果使用默认值,MFC 会以一种经过计算的方式分配内存,以避免内存碎片并在大多数情况下优化效率。

示例

请参阅 GetData 的示例。

另请参阅

MFC 示例 COLLECT
CObject 类
层次结构图
CObArray 类
集合类帮助器