Long before runtime type information (RTTI) was added to the C++
language specification, the MFC library designers realized that
they needed runtime access to an object's class
This appendix explains how the MFC library implements the class identification and dynamic creation features. You'll see how the DECLARE_DYNAMIC , DECLARE_DYNCREATE , and associated macros work, and you'll learn about the RUNTIME_CLASS macro and the CRuntimeClass structure.
If you wanted only an object's class name, you'd have an easy
time,
class CObject
{
public:
virtual char* GetClassName() const { return NULL; }
};
class CMyClass : public CObject
{
public:
static char s_lpszClassName[];
virtual char* GetClassName() const { return s_lpszClassName; }
};
char CMyClass::s_szClassName[] = "CMyClass";
Each derived class would override the virtual GetClassName function, which would return a static string. You would get an object's actual class name even if you used a CObject pointer to call GetClassName . If you needed the class name feature in many classes, you could save yourself some work by writing macros. A DECLARE_CLASSNAME macro might insert the static data member and the GetClassName function in the class declaration, and an IMPLEMENT_CLASSNAME macro might define the class name string in the implementation file.
In a real MFC program, an instance of the
CRuntimeClass
structure
struct CRuntimeClass
{
char m_lpszClassName[21];
int m_nObjectSize; // used for memory validation
CObject* (*m_pfnCreateObject)();
CObject* CreateObject();
};
![]()
The real MFC CRuntimeClass structure has additional data members and functions that navigate through the class's hierarchy. This navigation feature is not supported by the official C++ RTTI implementation.
This structure supports not only class name retrieval but also dynamic creation. Each class you derive from CObject has a static CRuntimeClass data member, provided that you use the MFC DECLARE_DYNAMIC , DECLARE_DYNCREATE , or DECLARE_SERIAL macro in the declaration and the corresponding IMPLEMENT macro in the implementation file. The name of the static data member is, by convention, class<class_name> . If your class were named CMyClass , the CRuntimeClass data member would be named classCMyClass .
If you want a pointer to a
class's
static
CRuntimeClass
object, you use the MFC
RUNTIME_CLASS
macro, defined as
#define RUNTIME_CLASS(class_name) (&class_name::class##class_name)
Here's how you use the macro to get the name string from a class name:
ASSERT(RUNTIME_CLASS(CMyClass)->m_lpszClassName == "CMyClass");
If you want the class name string from an object , you call the virtual CObject::GetRuntimeClass function. The function simply returns a pointer to the class's static CRuntimeClass object, just as earlier the GetClassName function returned the name string. Here's the function you'd write for CMyClass :
virtual CRuntimeClass* GetRuntimeClass()
const { return &classCMyClass; }
And here's how you'd call it:
ASSERT(pMyObject->GetRuntimeClass()->m_lpszClassName == "CMyClass");