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
GetAtmember 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
CPersonobjects. The array is derived from classCObArray, one of the nontemplate predefined classes.GetAtreturns a pointer to aCPersonobject. For typed pointer collection classes — arrays or lists — the first parameter specifies the base class; the second parameter specifies the type to store.The
CTypedPtrArrayclass 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 theforloop 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
GetHeadPositionandGetNextto 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
CPersonobjects. The list declaration resembles the one for the array in the procedure To iterate an array but is derived from classCObList.GetNextreturns a pointer to aCPersonobject.
To iterate a map
Use
GetStartPositionto get to the beginning of the map andGetNextAssocto 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
CStringkeys and stores pointers toCPersonobjects. When you use access functions such asGetNextAssoc, the class provides pointers toCPersonobjects. If you use one of the nontemplate map collections instead, you must cast the returnedCObjectpointer to a pointer to aCPerson.Note
For nontemplate maps, the compiler requires a reference to a
CObjectpointer 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.