MFC第三天——RTTI & Dynamic Creation

来源:互联网 发布:动态域名解析软件 编辑:程序博客网 时间:2024/05/19 11:37
上次提到了MFC程序的初始化,今天好好说说运行时类型识别(RTTI)和动态创建技术

1 CRuntimeClass和类别型录网
   首先,CRuntimeClass结构和类别型录网是实现RTTI和动态创建这两个技术的基础。
   因为早期技术比较单一,没有typeid运算符和template等概念,于是我们为每个类设计了一个对应的CRuntimeClass结构来储存该类的相关信息,将类库中所有类的          CRuntimeClass结构放入一个单向链表中,就构成了一个类别型录网,链表向上遍历类层次,直到表尾CObject::classCObject。

 1)CRuntimeClass结构:


struct CRuntimeClass
{
// Attributes
   LPCSTR m_lpszClassName;//类名
   int m_nObjectSize;//对象大小
   UINT m_wSchema; // schema number of the loaded class
   CObject* (PASCAL* m_pfnCreateObject)(); // NULL => abstract class
   CRuntimeClass* m_pBaseClass;//指向基类

   CObject* CreateObject();//
   static CRuntimeClass* PASCAL Load();


   // CRuntimeClass objects linked together in simple list
   static CRuntimeClass* pFirstClass; // start of class list指向表头
   CRuntimeClass* m_pNextClass;    // linked list of registered classes指向链表中的下一个类

};

加红色的三个变量都与动态创建有关,在下面说明。

   2)类别型录网:


2 DECLARE_DYNAMIC和IMPLEMENT_DYNAMIC宏
  我们用这两个宏,去在MFC中实现CRuntimeClass的声明和类别型录网的构成。
  1)#define DECLARE_DYNAMIC(class_name) 
     public: 
        static CRuntimeClass class##class_name; 
        virtual CRuntimeClass* GetRuntimeClass() const;
   注:DECLARE_DYNAMIC宏声明了一个与Cxxx类相对应的CRuntimeClass结构classCxxx。
  2)#define IMPLEMENT_DYNAMIC(class_name, base_class_name) \
        _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL)
     #define _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew) \
        static char _lpsz##class_name[] = #class_name; \
        CRuntimeClass class_name::class##class_name = { \
                _lpsz##class_name, sizeof(class_name), wSchema, pfnNew, \
                        RUNTIME_CLASS(base_class_name), NULL }; \
        static AFX_CLASSINIT _init_##class_name(&class_name::class##class_name); \
        CRuntimeClass* class_name::GetRuntimeClass() const \
                { return &class_name::class##class_name; } \
    其中,RUNTIME_CLASS宏:
     #define RUNTIME_CLASS(class_name) \
        (&class_name::class##class_name)
     和AFX_CLASSINIT结构:
     struct AFX_CLASSINIT
        { AFX_CLASSINIT(CRuntimeClass* pNewClass); };
     而AFX_CLASSINIT::AFX_CLASSINIT( CRuntimeClass* pNewClass)
     {
        pNewClass->m_pNextClass = CRuntimeClass::pFirstClass;
        CRuntimeClass::pFirstClass = pNewClass ;
     }
   注:IMPLEMENT_DYNAMIC宏,初始化classCxxx结构,并实现了链表。


3 RTTI

  有了类别型录网,现在可以说说类型识别技术了。


例:CView* pView = new CView;

        pView->IsKindOf(RUNTIME_CLASS(CWinApp));

        RUNTIME_CLASS(CWinApp)返回与CWinApp对应的CRuntimeClass结构指针

类型识别其实是靠m_pBaseClass的向上索引,两个类的CRuntimeClass指针的比较。


4 动态创建

  1)DECLARE_DYNCREATE和IMPLEMENT_DYNCREATE宏

       DECLARE_DYNCREATE:

        #define DECLARE_DYNCREATE(class_name)                   

                   DECLARE_DYNAMIC(class_name) \

                   static CObject* PASCAL CreateObject();

       IMPLEMENT_DYNCREATE宏:

       #define IMPLEMENT_DYNCREATE(class_name, base_class_name) \
        CObject* PASCAL class_name::CreateObject() \
                { return new class_name; } \
       _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, \
                class_name::CreateObject)

      注:这两个宏用于动态创建,且可以看到_DYNCREATE宏包含了_DYNAMIC宏。

  2)动态创建

     在头文件中加入DECLARE_DYNCREATE,在实现文件中加入IMPLEMENT_DYNCREATE,我们就可以进行动态创建类了。

     我们这里先把main中的动态创建语句写出来,反向思考看看动态创建的执行过程。

     void main()

     {

          ...

         CRuntimeClass* pClassRef;

         CObject* pOb;

         while(1)

         {

              if((pClassRef = CRuntimeClass::Load()) == NULL)

                 break;

              pOb = pClassRef -> CreateObject();

              if(pOb != NULL)

                 pOb->sayhello();

         }

     }

     首先执行到CRuntimeClass::Load(),看看load函数定义我们就会知道,它加载了一个类名,然后遍历类别型录网,当找到这个类对应的CRuntimeClass结构时,返回该结构的指针,否则返回null。然后到CreateObject(),再看看这个函数定义,它先判断m_pfnCreateObject指针是否为空,如果不为空,我们就调用该指针指向的函数classname::CreateObject()进行对象的创建,并返回对象指针完成动态创建。

 :值得一提的是m_pfnCreateObject指针,它是一个函数指针,保存着相应类的CreateObject()函数地址,而类的CreateObject()函数是在DECLARE_DYNCREATE宏中声明的(从上面可以看到),而且该函数其实是一个静态回调函数。所以,如果我们没有在类中加入DECLARE_DYNCREATE宏,m_pfnCreateObject指针为空,也就无法动态创建该类对象。


终于把这两个技术说了一遍,技术很强大,我希望能用浅显易懂的方式说给诸位,不当之处请见谅~

原创粉丝点击