Accessing All Members of a Collection
The new home for Visual Studio documentation is Visual Studio 2017 Documentation on docs.microsoft.com.
The latest version of this topic can be found at Accessing All Members of a Collection.
The MFC array collection classes — both template-based and not — use indexes to access their elements. The MFC list and map collection classes — both template-based and not — use an indicator of type POSITION to describe a given position within the collection. To access one or more members of these collections, you first initialize the position indicator and then repeatedly pass that position to the collection and ask it to return the next element. The collection is not responsible for maintaining state information about the progress of the iteration. That information is kept in the position indicator. But, given a particular position, the collection is responsible for returning the next element.
The following procedures show how to iterate over the three main types of collections provided with MFC:
Iterating an array
Iterating a list
Iterating a map
To iterate an array
Use sequential index numbers with the
GetAt
member function:CTypedPtrArray<CObArray, CPerson*> myArray; myArray.Add(new CPerson()); for (int i = 0; i < myArray.GetSize();i++) { CPerson* thePerson = myArray.GetAt(i); thePerson->AssertValid(); }
This example uses a typed pointer array that contains pointers to
CPerson
objects. The array is derived from classCObArray
, one of the nontemplate predefined classes.GetAt
returns a pointer to aCPerson
object. For typed pointer collection classes — arrays or lists — the first parameter specifies the base class; the second parameter specifies the type to store.The
CTypedPtrArray
class also overloads the [ ] operator so that you can use the customary array-subscript syntax to access elements of an array. An alternative to the statement in the body of thefor
loop above isCPerson* thePerson = myArray[i];
This operator exists in both const and non-const versions. The const version, which is invoked for const arrays, can appear only on the right side of an assignment statement.
To iterate a list
Use the member functions
GetHeadPosition
andGetNext
to work your way through the list:CTypedPtrList<CObList, CPerson*> myList; myList.AddHead(new CPerson()); POSITION pos = myList.GetHeadPosition(); while(pos != NULL) { CPerson* thePerson = myList.GetNext(pos); thePerson->AssertValid(); }
This example uses a typed pointer list to contain pointers to
CPerson
objects. The list declaration resembles the one for the array in the procedure To iterate an array but is derived from classCObList
.GetNext
returns a pointer to aCPerson
object.
To iterate a map
Use
GetStartPosition
to get to the beginning of the map andGetNextAssoc
to repeatedly get the next key and value from the map, as shown by the following example:CMap<CString, LPCTSTR, CPerson*, CPerson*> myMap; CPerson myPerson; myMap.SetAt(_T("Bill"), &myPerson); POSITION pos = myMap.GetStartPosition(); while(pos != NULL) { CPerson* pPerson; CString string; // Get key (string) and value (pPerson) myMap.GetNextAssoc(pos, string, pPerson); // Use string and pPerson }
This example uses a simple map template (rather than a typed pointer collection) that uses
CString
keys and stores pointers toCPerson
objects. When you use access functions such asGetNextAssoc
, the class provides pointers toCPerson
objects. If you use one of the nontemplate map collections instead, you must cast the returnedCObject
pointer to a pointer to aCPerson
.Note
For nontemplate maps, the compiler requires a reference to a
CObject
pointer in the last parameter toGetNextAssoc
. On input, you must cast your pointers to that type, as shown in the next example.The template solution is simpler and helps provide better type safety. The nontemplate code is more complicated, as you can see here:
CMapStringToOb myMap; // A nontemplate collection class CPerson myPerson; myMap.SetAt(_T("Bill"), &myPerson); POSITION pos = myMap.GetStartPosition(); while(pos != NULL) { CPerson* pPerson; CString string; // Gets key (string) and value (pPerson) myMap.GetNextAssoc(pos, string, (CObject*&)pPerson); ASSERT(pPerson->IsKindOf( RUNTIME_CLASS(CPerson))); // Use string and pPerson }
For more information, see Deleting All Objects in a CObject Collection.