The AssertValid member function is provided in CObject to allow run-time checks of an object’s internal state. AssertValid typically performs assertions on all the object’s member variables to see if they contain valid values. For example, AssertValid can check that all pointer member variables are not NULL. If the object is invalid, AssertValid halts the program.
Although you are not required to override AssertValid when you derive your class from CObject, you can make your class safer and more reliable by doing so. The following example shows how to declare the AssertValid function in the class declaration:
class CPerson : public CObject
{
protected:
CString m_strName;
float m_salary;
public:
#ifdef _DEBUG
virtual void AssertValid() const; // Override
#endif
// ...
};
When you override AssertValid
, first call AssertValid for the base class. Then use the ASSERT macro to check the validity of the members unique to your derived class, as shown by the following example:
#ifdef _DEBUG
void CPerson::AssertValid() const
{
// call inherited AssertValid first
CObject::AssertValid();
// check CPerson members...
ASSERT( !m_strName.IsEmpty()); // Must have a name
ASSERT( m_salary > 0 ); // Must have an income
}
#endif
If any of the member variables of your class store objects, you can use the ASSERT_VALID macro to test their internal validity (if their classes override AssertValid). The following example shows how this is done.
Consider a class CMyData
, which stores a CObList in one of its member variables. The CObList variable, m_DataList
, stores a collection of CPerson
objects. An abbreviated declaration of CMyData
looks like this:
class CMyData : public CObject
{
// Constructor and other members ...
protected:
CObList* m_pDataList;
// Other declarations ...
public:
#ifdef _DEBUG
virtual void AssertValid( ) const; // Override
#endif
// Etc. ...
};
The AssertValid override in CMyData
looks like this:
#ifdef _DEBUG
void CMyData::AssertValid( ) const
{
// Call inherited AssertValid
CObject::AssertValid( );
// Check validity of CMyData members
ASSERT_VALID( m_pDataList );
// ...
}
#endif
CMyData
uses the AssertValid mechanism to add validity tests for the objects stored in its data member to the validity test of the CMyData
object itself. The overriding AssertValid of CMyData
invokes the ASSERT_VALID macro for its own m_pDataList member variable.
The chain of validity testing might stop at this level, but in this case class CObList overrides AssertValid too, and the ASSERT_VALID macro causes it to be called. This override performs additional validity testing on the internal state of the list. If an assertion failure occurs, diagnostic messages are printed, and the program halts.
Thus, a validity test on a CMyData
object leads to additional validity tests for the internal states of the stored CObList list object. With a little more work, the validity tests could include the CPerson
objects stored in the list as well. You could derive a class CPersonList
from CObList and override AssertValid. In the override, you would call CObject::AssertValid and then iterate through the list, calling AssertValid
on each CPerson
object stored in the list. The CPerson
class shown at the beginning of this topic already overrides AssertValid.
This is a powerful mechanism when you build for debugging. When you subsequently build for release, the mechanism is turned off automatically.
Users of an AssertValid
function of a given class should be aware of the limitations of this function. A triggered assertion indicates that the object is definitely bad and execution will halt. However, a lack of assertion only indicates that no problem was found, but the object isn’t guaranteed to be good.