100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
C++

MFC Collection Classes

A tour of MFC's template and legacy collection classes for storing arrays, lists, and maps of data, and how to choose between them.

Collections and UtilitiesIntermediate9 min readJul 10, 2026
Analogies

Overview of MFC Collection Classes

MFC ships two generations of collection classes. The older, non-template classes such as CObArray, CObList, and CMapStringToOb store CObject pointers or specific fixed types and predate C++ templates being widely usable in Microsoft's toolchain. The newer template-based classes, CArray<TYPE,ARG_TYPE>, CList<TYPE,ARG_TYPE>, and CMap<KEY,ARG_KEY,VALUE,ARG_VALUE>, let you store any type safely with compile-time type checking, and are the ones you should reach for in new code.

🏏

Cricket analogy: Choosing between legacy and template collections is like a coach deciding between an all-rounder squad picked by fixed roles (batsman, bowler, keeper) versus a flexible XI like Ravindra Jadeja who can be slotted anywhere the match situation demands.

Array-Based Collections: CArray and Friends

CArray<TYPE,ARG_TYPE> is a dynamically growable array, similar in spirit to std::vector but predating it in MFC's design. You call SetSize(nCount, nGrowBy) to preallocate storage and control how many extra elements are reserved each time the array must reallocate, GetSize() to query the current element count, and ElementAt(nIndex) or operator[] for direct access. Because CArray stores elements contiguously, random access is O(1), but inserting or removing an element in the middle requires shifting every subsequent element.

🏏

Cricket analogy: SetSize with nGrowBy is like a scorer who reserves extra rows on the scoresheet in advance, anticipating that a team like England might need many more overs recorded if the innings runs long, rather than adding one row at a time.

List-Based Collections: CList

CList<TYPE,ARG_TYPE> implements a doubly linked list, which trades random-access speed for cheap insertion and removal anywhere in the sequence. Navigation uses an opaque POSITION handle rather than an integer index: GetHeadPosition() and GetTailPosition() return starting points, and GetNext(pos) or GetPrev(pos) advance through the list while returning the element at the old position. AddHead() and AddTail() insert in O(1) time, which makes CList well suited to queues, undo stacks, and scenarios with frequent mid-sequence insertion.

🏏

Cricket analogy: Walking a CList with POSITION and GetNext is like a commentator following the over-by-over sequence of a Test match ball by ball rather than jumping straight to over forty, since each delivery only knows the one before and after it.

Map-Based Collections: CMap

CMap<KEY,ARG_KEY,VALUE,ARG_VALUE> is a hash table associating keys with values. SetAt(key, value) inserts or updates an entry, Lookup(key, value) returns TRUE and fills value by reference if the key exists, and RemoveKey(key) deletes an entry. Because it is hash-based, average-case lookup is O(1), but you can tune GetHashTableSize() and InitHashTable() to control collision behavior for large datasets, and iteration order is unspecified since it depends on hash bucket placement rather than insertion order.

🏏

Cricket analogy: Lookup by key is like a scorer instantly finding a player's career average by name in a database rather than scanning every match card in order, similar to instantly pulling up Sachin Tendulkar's stats.

The legacy classes CObArray, CObList, and CMapStringToOb are still present in MFC for backward compatibility with older codebases, but they store CObject* and require RTTI-style dynamic casting to recover the concrete type. New code should prefer the template classes CArray, CList, and CMap, or better yet std::vector, std::list, and std::map from the standard library where MFC interop is not required.

ARG_TYPE in CArray, CList, and CMap is often a reference type used for parameter passing efficiency, but passing a temporary object whose lifetime ends before the collection uses it can leave a dangling reference. Always verify that the value passed to Add(), SetAt(), or similar methods outlives the call, especially when ARG_TYPE is something like const CString&.

  • MFC has legacy CObArray/CObList/CMap-style classes and modern template classes CArray, CList, and CMap.
  • CArray offers O(1) random access via ElementAt but O(n) insertion in the middle.
  • CList offers O(1) insertion at head or tail via a doubly linked list navigated with POSITION handles.
  • CMap provides average O(1) key-based lookup using a hash table via SetAt, Lookup, and RemoveKey.
  • SetSize with nGrowBy preallocates CArray storage to reduce reallocation overhead.
  • Legacy CObject-based collections remain for backward compatibility but lack compile-time type safety.
  • Watch for dangling references when ARG_TYPE parameters are passed temporary values.

Practice what you learned

Was this page helpful?

Topics covered

#MFCMicrosoftFoundationClassesStudyNotes#MicrosoftTechnologies#MFCCollectionClasses#MFC#Collection#Classes#Array#OOP#StudyNotes#SkillVeris