23.5 MFC classes are shallow wrappers

23.5 MFC classes are shallow wrappers

You might wonder what the members of the various kinds of MFC classes are. As it turns out, most of the classes have only one member, which is public. These members all have a name which starts with a lower-case m and an underscore : m_ . Thus, for instance, the only data member of a CWnd is a public HWND called m_hWnd . What's an HWND , anyway? It means 'handle to a window.' In similar fashion, if you look inside a CDC , you'll find a public HDC field called m_hDC , where an HDC is a 'handle to a device context.'

Handles can be described as pointers to pointers. We can think of a handle as being like an index into a table of memory pointers. Saving an object's memory pointer at a second remove allows the operating system to move around the object's memory and change its memory pointer, while keeping the same handle pointer to locate the current value of the memory pointer.

As a practical matter, C++ really doesn't want you to worry about the data members of a class. You're supposed to use accessors to get information about what's in an object, use mutators to change an object's contents, and use the class methods to do things with the object. So usually we don't think too much about the m_ fields inside our classes. But now and then we'll notice that the implementation of an MFC method refers to one of the class's m_ data fields.

If you've ever worked with Win32 programming, you'll be familiar with the fact that Windows programming involves a number of special data whose names start with the letter H . An HWND is a type that represents a window, an HDC is a type that represents a 'device context,' an HPEN is a kind of virtual drawing object called a 'pen,' and so on. These types all start with the letter H , because rather than being visible data structures, they are handles for hidden Windows data structures.

The basic idea for MFC is instead of using handles to secret data structures, we should start using real pointers to real C++ objects. This means two things. For just about every H WHATEVER type from Win32, MFC defines a corresponding C Whatever class. Thus, HWND is replaced by CWnd , HDC by CDC , HBRUSH by CBrush , HICON by CSpriteIcon , HBITMAP by CBitmap , and so on.

In addition, most Win32 functions that had an H??? as the first argument type now become member functions of the corresponding C??? class. Thus GetDC(HWND hwnd) becomes CWnd::GetDC() . And all of the graphics design interface (GDI) functions that had an HDC as the first argument are now CDC member functions; for instance Rectangle(HDC hdc, int left, int top, int right, int bottom) is now CDC::Rectangle(int left, int top, int right, int bottom) . The formerly explicit H WHATEVER argument is now an implicit C Whatever argument that appears as the object calling the method. Where formerly we wrote Rectangle(hdc, 10, 20, 100, 200) , we'll now write cdc.Rectangle(10, 20, 100, 200) or pDC-> Rectangle(10, 20, 100, 200) .

Many function arguments and function return values that used to be H WHAT EVER HANDLE types are now usually pointers to C Whatever objects. Thus, for example we might see code like this in Win32.

 myFunction(HWND hwnd)  {      HDC hdc;      hdc = GetDC(hwnd)      TextOut(hdc, ...);      ...  } 

Converting all the H??? to C??? and changing from handles to pointers, we'd expect to see something like the following.

 myFunction(CWnd *pWnd)  {      CDC *pDC;      pDC = pWnd->GetDC();      pDC->TextOut(...);      ...  } 

Or what might happen is that myFunction is actually a member function of CWnd now, with code like the following. (Remember that the word 'this' refers to the calling object when used inside the code implementing a class method.)

 void CWnd::myFunction()  {      CDC *pDC;      pDC = this->GetDC();      pDC->TextOut(...);      ...  } 

What is actually inside these new classes like CWnd , CDC , and CBrush ? What are their data members and what are their class methods? The answers are both a relief and an anticlimax.

Most of the C Whatever classes have only a single data member, which is a public field of type H WHATEVER named m_h Whatever . Most of the C Whatever member methods are just modifications of regular old API functions that used to have a C Whatever as the first argument.

The MFC classes are in fact 'shallow wrappers' around regular old Win32 objects. Thus, the only data member of a CWnd is a public HWND called m_hWnd . A CBrush's single data member is a public HANDLE called m_hObject ; normally this is in fact an HBRUSH . (The CBrush class is a child of the CObject class.) A CDC has two data members that are public HDCs called m_hDC and m_hAttribDC . (Normally these are equal to each other, but in the case where m_hDC represents a special metafile or is derived from a printer, m_hAtrribDC is derived from an onscreen window.)

The good news is that MFC is not very different from Win32, so if you already know Windows programming there's not all that much new to learn. The bad news is that if the Windows programming language was a confused , screwed-up mess, MFC is, if anything, even gnarlier. Like living organisms, real-world computer-languages evolve by successive mutations , rather than being written clean and fresh from the ground up. Every now and then there is a fresh new language, but eventually it too gets all crusty and frobby and tweaked after being out in the world, and (if it is lucky) being heavily used for a few years .

Software Engineering and Computer Games
Software Engineering and Computer Games
Year: 2002
Pages: 272

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net