Programming Microsoft Visual C++
Authors: Kruglinski D. J. Wingo S. Shepherd G.
Published year: 1997
Pages: 326-328/332
Buy this book on amazon.com >>
Appendix B

MFC Library Runtime Class Identification and Dynamic Object Creation

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 name and to the position of the class in the hierarchy. Also, the document-view architecture (and, later, COM class factories) demanded that objects be constructed from a class specified at runtime. So the MFC team created an integrated macro-based class identification and dynamic creation system that depends on the universal CObject base class. And in spite of the fact that the Visual C++ version 6.0 compiler supports the ANSI RTTI syntax, the MFC library continues to use the original system, which actually has more features.

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.

Getting an Object's Class Name at Runtime

If you wanted only an object's class name, you'd have an easy time, assuming that all your classes were derived from a common base class, CObject . Here's how you'd get the class name:

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.

The MFC CRuntimeClass Structure and the RUNTIME_CLASS Macro

In a real MFC program, an instance of the CRuntimeClass structure replaces the static s_lpszClassName data member shown above. This structure has data members for the class name and the object size ; it also contains a pointer to a special static function, CreateObject , that's supposed to be implemented in the target class. Here's a simplified version of CRuntimeClass :

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 follows :

#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");
Programming Microsoft Visual C++
Authors: Kruglinski D. J. Wingo S. Shepherd G.
Published year: 1997
Pages: 326-328/332
Buy this book on amazon.com >>

Similar books on Amazon