- Table of Contents
- Copyright
- About the Authors
- About the Contributors
- Acknowledgments
- Tell Us What You Think!
- Introduction
- How to Use This Book
- What You Need to Use This Book
- What's New in Visual C++ 6.0
- Contacting the Main Author
- Part I: Introduction
- Chapter 1. The Visual C++ 6.0 Environment
- Part II: MFC Programming
- Chapter 2. MFC Class Library Overview
- Chapter 3. MFC Message Handling Mechanism
- Chapter 4. The Document View Architecture
- Chapter 5. Creating and Using Dialog Boxes
- Chapter 6. Working with Device Contexts and GDI Objects
- Chapter 7. Creating and Using Property Sheets
- Chapter 8. Working with the File System
- Chapter 9. Using Serialization with File and Archive Objects
- Part III: Internet Programming with MFC
- Chapter 10. MFC and the Internet Server API (ISAPI)
- Chapter 11. The WinInet API
- Chapter 12. MFC HTML Support
- Part IV: Advanced Programming Topics
- Chapter 13. Using the Standard C++ Library
- Chapter 14. Error Detection and Exception Handling Techniques
- Chapter 15. Debugging and Profiling Strategies
- Chapter 16. Multithreading
- Chapter 17. Using Scripting and Other Tools to Automate the Visual C++ IDE
- Part V: Database Programming
- Chapter 18. Creating Custom AppWizards
- Chapter 19. Database Overview
- Chapter 20. ODBC Programming
- Chapter 21. MFC Database Classes
- Chapter 22. Using OLE DB
- Chapter 23. Programming with ADO
- Part VI: MFC Support for COM and ActiveX
- Chapter 24. Overview of COM and Active Technologies
- Chapter 25. Active Documents
- Chapter 26. Active Containers
- Chapter 27. Active Servers
- Chapter 28. ActiveX Controls
- Part VII: Using the Active Template Library
- Chapter 29. ATL Architecture
- Chapter 30. Creating COM Objects Using ATL
- Chapter 31. Creating ActiveX Controls Using ATL
- Chapter 32. Using ATL to Create MTS and COM+ Components
- Part VIII: Finishing Touches
- Chapter 33. Adding Windows Help
- Part IX: Appendix
Debugging Support
Because CObject is the base class for almost all other classes in the MFC, it serves as a convenient place to stash a few very important debugging features.
AssertValid()
If you want to be able to verify that an object of your class is valid, you can override the AssertValid() member function of CObject. Like many other debug features, this should only be implemented in builds where the preprocessor symbol _DEBUG is defined. To implement an
AssertValid() function for your class, the declaration for your class should look like the following:
class CMyClass : public CObject
{
// other stuff for your class
public:
#ifdef _DEBUG
virtual void AssertValid() const;
#endif
};
Now you need to implement your AssertValid() function. This function should perform a quick check that the elements of your class are in order. Your implementation should look something like this:
#ifdef _DEBUG
void CEmployee::AssertValid()
{
// validate the base class
CObject::AssertValid();
// validate this class
ASSERT(m_EmpNo != 0);
} // end CEmployee::AssertValid()
#endif
You should perform all your validity tests with the ASSERT macro (and derivatives like ASSERT_KINDOF). You can use AssertValid() in your applications by calling the ASSERT_VALID macro, which takes a pointer to the object to be validated. This macro, like many other debug macros, will not generate any code in non-debug builds, so you won't need to hassle with all those pesky #ifdefs.
The ASSERT Macro
Because I have mentioned asserts several times already, it's about time you look at them in more detail. The ASSERT macro takes any expression that evaluates to a Boolean expression. If this expression is true (nonzero), all is well and the app goes on its merry way. If, however, the expression is false (0), a dialog box like that in Figure 2.9 will appear.
Figure 2.9 The Assertion dialog box.
This dialog box gives you three choices. You may choose Abort to stop your app right there; or you can choose Ignore to close the dialog and press on; or you can choose Retry, which enables you to jump right into the debugger at the point that the ASSERT failed, even if you did not start the application in the debugger. From this point, you can easily use the Call Stack window to figure out just where in your code things went amiss.
Remember that the ASSERT macro does not generate any code in non-debug builds. It will not even evaluate the expression. If you want to have the expression evaluated in release builds, you can use the VERIFY macro instead.
Dump()
Another important debugging feature of the CObject class is the Dump() function. This is useful when you want to spit out information about the current state of your class object periodically, or when you have noticed a problem. Once again, this feature should not be implemented in non-debug builds. To use the Dump() function in your classes, you insert code something like this:
class CEmployee : public CObject
{
public:
#ifdef _DEBUG
virtual void Dump(CDumpContext& dc) const;
#endif
int m_EmpNo;
CString m_Name;
// Other class stuff
} // end class CEmployee
Your implementation would include code such as this:
#ifdef _DEBUG
void CEmployee::Dump(CDumpContext& dc) const
{
// first, call base class Dump
CObject::Dump(dc);
// then dump this class
dc << "Employee Number: " << m_EmpNo << "\n"
<< "Employee Name: " << m_Name << "\n";
} // end CEmployee::Dump()
#endif
If you are running your application under the Visual C++ debugger, MFC will set up the dump context passed to Dump() to send its output to the Output window of the debugger.
The insertion operator for the dump context that is used in the examples is defined for the following types:
- BYTE
- WORD
- DWORD
- int
- UINT
- LONG
- double
- float
- CObject*
- CObject&
- void*
- LPCTSTR
- LPCWSTR
- LPCSTR
If the type you want to dump isn't supported, you can generally get by with a simple cast. After all, the data is just going to be converted to a string for output.
The TRACE() Macro
In addition to the Dump() function, your application can write to the debug context with the TRACE() macro provided by MFC. The TRACE() macro works much like printf(). It accepts a string that may include placeholders for other variables, using the same % variables that printf() uses, except TRACE() does not support floating-point variables. The TRACE() macros will, however, support Unicode strings.
With the MFC Tracer application (TRACER.EXE), included in the Tools menu of Developer Studio, you can enable or disable several sorts of trace messages provided by MFC's internals, as well as disable tracing altogether.
If you wish to assign MFC's dump context—and the TRACE() and Dump() output that goes with it—to something other than the debugger's Output window, see the documentation for the CDumpContext and Dumpinit.cpp in the MFC source directory, which declares CDumpContext afxDump. Unfortunately, the details of doing this are beyond the scope of this book.
Putting It All Together | Next Section

Account Sign In
View your cart