Programming Windows with MFC, Second Edition

[Previous] [Next]

The MFC collection classes with Ptr and Ob in their names (the "Ptr" and "Ob" classes) provide convenient implementations of containers that store generic (void) pointers and containers that store pointers to MFC objects—that is, objects created from classes derived from CObject. The problem with the Ptr and Ob classes is that they're too generic. Using them typically requires lots of type casting, which is anathema to many C++ programmers and poor programming practice besides.

MFC's typed pointer classes—a set of three template classes designed to handle collections of pointers in a type-safe manner—offer a convenient solution to the problem of storing pointers without compromising type safety. The typed pointer classes are listed in the following table.

Collection Classes for Pointers

Class Name Description
CTypedPtrArray Manages arrays of pointers
CTypedPtrList Manages linked lists of pointers
CTypedPtrMap Manages maps that use pointers as items or keys

Suppose you're writing a drawing program and you've written a class named CLine that represents lines drawn on the screen. Each time the user draws a line, you create a new CLine object. You need somewhere to store CLine pointers, and because you want to be able to add and delete pointers anywhere in the collection without incurring a performance hit, you decide to use a linked list. Because you derived CLine from CObject, CObList would seem a natural fit.

CObList will do the job, but every time you retrieve a CLine pointer from the list, you must cast it to CLine* because CObList returns CObject pointers. CTypedPtrList offers a clean alternative that requires no casting. Here's a code sample that demonstrates this point:

CTypedPtrList<CObList, CLine*> list; // Populate the list. for (int i=0; i<10; i++) { int x = i * 10; CLine* pLine = new CLine (x, 0, x, 100); list.AddTail (pLine); } // Enumerate the items in the list. POSITION pos = list.GetHeadPosition (); while (pos != NULL) CLine* pLine = list.GetNext (pos); // No casting!

When you retrieve a CLine pointer with GetNext, you get back a CLine pointer that requires no casting. That's type safety.

CTypedPtrList and the other typed pointer classes work by deriving from the class whose name is specified in the first template parameter. Inside the derived class are type-safe member functions that wrap the corresponding member functions in the base class. You can call any of the functions in the base class or in the derived class, but where they overlap, you'll normally use the type-safe versions instead. In general, you should use Ob classes as base classes for collections that hold pointers to objects derived from CObject, and Ptr classes as base classes for collections that hold pointers to other types of objects.

As is true of all MFC collection classes that store pointers, deleting pointers from an array, a list, or a map doesn't delete the items that the pointers point to. Therefore, before emptying a list of CLine pointers, you'll probably find it necessary to delete the CLines, too:

POSITION pos = list.GetHeadPosition (); while (pos != NULL) delete list.GetNext (pos); list.RemoveAll ();

Remember: If you don't delete the CLines, nobody will. Don't assume that the collection classes will delete them for you.

Категории