Tuesday, September 18, 2007

CObject services

CObject Services :
Cobject provides basic services needed for all the classes.

1.Supports serialization
2.run-time class information
3.Dynamic Object Creation
4.Object diagnostic output (Debugging)
5.Compatibility with collection classes

The first-level macros, DECLARE_DYNAMIC and IMPLEMENT_DYNAMIC, permit run-time access to the class name
and its position in the hierarchy. This, in turn, allows meaningful diagnostic dumping and dynamic Object creation.

The second-level macros, DECLARE_SERIAL and IMPLEMENT_SERIAL, include all the functionality of the first-level macros,
and they enable an object to be “serialized” to and from an “archive.”

MFC collection classes are derived from CObject So we can store any class( derived from CObject) into the collection class.



Serialization Example :
----------------------------------

class CMyObject : public CObject
{
// ...Member functions
public:
CMyObject() { }
virtual void Serialize( CArchive& ar ) { }

// Implementation
protected:
DECLARE_SERIAL( CMyObject )
};


class COtherObject : public CObject
{
// ...Member functions
public:
COtherObject() { }
virtual void Serialize( CArchive& ar ) { }

// Implementation
protected:
DECLARE_SERIAL( COtherObject )
};


class CCompoundObject : public CObject
{
// ...Member functions
public:
CCompoundObject();
virtual void Serialize( CArchive& ar );

// Implementation
protected:
CMyObject m_myob; // Embedded object
COtherObject* m_pOther; // Object allocated in constructor
CObject* m_pObDyn; // Dynamically allocated object
//..Other member data and implementation

DECLARE_SERIAL( CCompoundObject )
};

IMPLEMENT_SERIAL(CMyObject,CObject,1)
IMPLEMENT_SERIAL(COtherObject,CObject,1)
IMPLEMENT_SERIAL(CCompoundObject,CObject,1)


CCompoundObject::CCompoundObject()
{
m_pOther = new COtherObject; // Exact type known and object already
//allocated.
m_pObDyn = NULL; // Will be allocated in another member function
// if needed, could be a derived class object.
}

void CCompoundObject::Serialize( CArchive& ar )
{
CObject::Serialize( ar ); // Always call base class Serialize.
m_myob.Serialize( ar ); // Call Serialize on embedded member.
m_pOther->Serialize( ar ); // Call Serialize on objects of known exact type.

// Serialize dynamic members and other raw data
if ( ar.IsStoring() )
{
ar << m_pObDyn;
// Store other members
}
else
{
ar >> m_pObDyn; // Polymorphic reconstruction of persistent
// object
//load other members
}
}





RunTimeClass Information Support Example :
====================================


// in .H file
class CPerson : public CObject
{
DECLARE_DYNAMIC( CPerson )
public:
CPerson(){};

// other declaration
};


// in .CPP file
IMPLEMENT_DYNAMIC( CPerson, CObject )


void SomeFunction(void)
{
CObject* pMyObject = new CPerson;

if(pMyObject->IsKindOf( RUNTIME_CLASS( CPerson ) ) )
{
//if IsKindOf is true, then cast is all right
CPerson* pmyPerson = (CPerson*) pMyObject ;
...
delete pmyPerson;
}
...
delete [MyObject];
}


Dynamic Object Creation :
-----------------------------------


To dynamically create an object given its run-time class

Use the following code to dynamically create an object by using the CreateObject function of the CRuntimeClass.
Note that on failure, CreateObject returns NULL instead of raising an exception:

CRuntimeClass* pRuntimeClass = RUNTIME_CLASS( CMyClass );
CObject* pObject = pRuntimeClass->CreateObject();
ASSERT( pObject->IsKindOf( RUNTIME_CLASS( CMyClass ) ) );


Object diagnostic output :
------------------------------------

Dumping Object Contents :

This topic explains how to get a diagnostic dump of the contents ofour objects.

When deriving a class from CObject, we have the option to override the Dump member function and write a textual representation of the object’s member variables to a dump context which is similar to an I/O stream. Like an I/O stream, you can use the insertion (<<) operator to send data to a CDumpContext.

we do not have to override Dump when you derive a class from CObject. However, if we use other diagnostic features for debugging, providing the capability for dumping an object and viewing its contents is very helpful and highly recommended.

Note Before we can dump objects, we must enable diagnostic tracing so we can see the results of our dump in the debugger.


To override the Dump member function

Call the base class version of Dump to dump the contents of a base class object.


Write a textual description and value for each member variable of your derived class.
The declaration of the Dump function in the class declaration looks like:

class CPerson : public CObject
{
public:
#ifdef _DEBUG
virtual void Dump( CDumpContext& dc ) const;
#endif

CString m_firstName;
CString m_lastName;
// etc. ...
};

Note Since object dumping only makes sense when you are debugging your program, the declaration of the Dump function is bracketed with an #ifdef _DEBUG / #endif block.

In the following example from an implementation file for the class CPerson, the Dump function’s first statement calls the Dump member function for its base class. It then writes a short description of each member variable along with the member’s value to the diagnostic stream.

#ifdef _DEBUG
void CPerson::Dump( CDumpContext& dc ) const
{
// call base class function first
CObject::Dump( dc );

// now do the stuff for our specific class
dc << "last name: " << m_lastName << "\n"
<< "first name: " << m_firstName << "\n";
}
#endif

Note Again, notice that the definition of the Dump function is bracketed by #ifdef _DEBUG / #endif directives. If you refer to afxDump in a program linked with the nondebug libraries, you will get unresolved externals errors at link time.

To send Dump output to afxDump

You must supply a CDumpContext argument to specify where the dump output will go when you call the Dump function for an object.
MFC supplies a predefined CDumpContext object named afxDump that you will normally use for routine object dumping.
The following example shows how to use afxDump:

CPerson* pMyPerson = new CPerson;
// set some fields of the CPerson object...
//...
// now dump the contents
#ifdef _DEBUG
pMyPerson->Dump( afxDump );
#endif

In Windows NT, afxDump output is sent to the debugger, if present. Otherwise, you won’t get any afxDump output.

Note afxDump is defined only in the debug version of MFC.

No comments: