In addition to what Christina said, we would like to add the following. MFC allows you to easily get run-time information about any CObject
-derived classes. The CRuntimeClass
class describes type information about some other class. Most of MFC classes have run-time class information. You can also describe your classes. A pointer to the CRuntimeClass
object allows you to create an instance of the class which it describes and easily find out whether it is derived from some other known class described by other pointer to the CRuntimeClass
object. You can describe your class using the following ways:
1) Add the DECLARE_DYNAMIC
/IMPLEMENT_DYNAMIC
to the implementation of your class, which makes it possible to get run-time description of your classes and determineif one class is derived from another class:
CYourDialogClass1 * p1 = . . .
CYourDialogClass2 * p2 = . . .
CRuntimeClass * pRtc1 = p1->GetRuntimeClass();
ASSERT( pRtc1 != NULL );
CRuntimeClass * pRtc2 = p2->GetRuntimeClass();
ASSERT( pRtc2 != NULL );
if( pRtc2->IsDerivedFrom( pRtc1 ) )
::AfxMessageBox( _T("CYourDialogClass2 derived from CYourDialogClass1") );
else if( pRtc1->IsDerivedFrom( pRtc2 ) )
::AfxMessageBox( _T("CYourDialogClass1 derived from CYourDialogClass2") );
else
::AfxMessageBox( _T("There is no inheritance between CYourDialogClass1 and CYourDialogClass1") );
You can do the same using class names and the
RUNTIME_CLASS()
preprocessor function:
CYourDialogClass1 * p1 = . . .
CYourDialogClass2 * p2 = . . .
if( p2->IsKindOf( RUNTIME_CLASS( CYourDialogClass1 ) ) )
::AfxMessageBox( _T("CYourDialogClass2 derived from CYourDialogClass1") );
else if( p1->IsKindOf( RUNTIME_CLASS( CYourDialogClass2 ) ) )
::AfxMessageBox( _T("CYourDialogClass1 derived from CYourDialogClass2") );
else
::AfxMessageBox( _T("There is no inheritance between CYourDialogClass1 and CYourDialogClass1") );
If some function in your code has a
CWnd * pWnd
parameter and some part of this function expects that this
CWnd *
pointer must be a pointer to the
CDialog *
object, you can use the following assertion:
ASSERT( pWnd->IsKindOf( RUNTIME_CLASS( CButton ) ) );
Or this:
ASSERT_KINDOF( CButton, pWnd );
If you need to use a
CButton *
pointer after that, then you can get it using the following code:
CButton * pButton = STATIC_DOWNCAST( CButton, pWnd );
The line of code above should be invoked if you know that the
pWnd
pointer will really point to a
CButton</coded> object. If you do not know this and it may point to a <code>CButton
object in some cases and to other class object in some other cases, you should you use type checking assertion failures like described above. You should analyze the type of the
CWnd * pWnd
pointer dynamically:
CButton * pButton = DYNAMIC_DOWNCAST( CButton, pWnd );
if( pButton != NULL )
{
::AfxMessageBox( _T("pWnd is button") );
return . . .
}
CComboBox * pComboBox = DYNAMIC_DOWNCAST( CComboBox, pWnd );
if( pComboBox != NULL )
{
::AfxMessageBox( _T("pWnd is combo box") );
return . . .
}
. . .
2) Add the
DECLARE_DYNCREATE
/
IMPLEMENT_DYNCREATE
into the implementation of your class. This includes all the previously described features plus allows you to create your classes dynamically by their run-time descriptions. Let us say you have saved the description of your class in some part of your code:
CYourDialogClass1 * p1 = . . .
CRuntimeClass * pRtc1 = p1->GetRuntimeClass();
ASSERT( pRtc1 != NULL );
The
pRtc1
is the description of your class. Then some function in your code can receive a
pRtc1
pointer in a parameter and invoke the following:
CObject * pObject = pRtc1->CreateObject();
The
pObject
pointer is really a CYourDialogClass1 pointer and you can check and use its type as described above.
3) Add the
DECLARE_SERIAL
/
IMPLEMENT_SERIAL
to the implementation of your class. This includes both features described above plus allows you to load/save objects with run-time class information from/to MFC archives. If you have a pointer to some object, then you can serialize it with its run-time type:
CArchive & ar = . . .
CObject * pObject = . . .
ASSERT_VALID( pObject );
CRuntimeClass * pRTC = pObject->GetRuntimeClass();
ASSERT( pRTC != NULL );
ar.WriteClass( pRTC );
pObject->Serialize( ar );
This allows you to load an object of serializeable type from the archive dynamically. I.e. object of exactly the same type will be created from the archived data:
CArchive & ar = . . .
CRuntimeClass * pRTC = ar.ReadClass();
ASSERT( pRTC != NULL );
CObject * pObject = pRTC->CreateObject();
ASSERT_VALID( pObject );
pObject->Serialize( ar );