• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            cc

              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
              38 隨筆 :: 14 文章 :: 21 評論 :: 0 Trackbacks

                                 ////////////////////////////////////////////////////////////////////////////////////
                                 /********* 文章系列:MFC技術內幕系列***********/
                                 /************MFC技術內幕系列之(三)***********/
                                 /*文章題目:MFC執行期類型識別與動態創建技術內幕*/
                                 /*                   Copyright(c)2002 bigwhite                    */
                                 /*                          All rights Reserved                         */
                                 /*******關鍵字:執行期類型識別,動態創建*******/
                                 /*                          時間:2002.7.23                            */
                                 /*    注釋:本文所涉及的程序源代碼均在Microsoft    */
                                 /          Visual Studio.Net Enterprise Architect Edition      /
                                 /*                  開發工具包提供的源代碼中                  */
                                
            ////////////////////////////////////////////////////////////////////////////////////////////////
            引言:
                眾所周知,微軟的MFC Application Framework建立在一系列先進的程序設計技術上的。比如:消息映射機制,命令傳遞機制,執行期類型識別與動態創建技術及文檔序列化技術等。其中執行期類型識別與動態創建技術是其中最重要的技術之一。微軟在MFC中用一些神秘的宏實現了這種機制,但是對于學習MFC程序設計的初學者來說它卻成為了一大難點,所以在這篇文章中我將詳細地為大家挖掘其中的內幕。

            正文:
                MFC執行期類型識別與動態創建技術是借助CRuntimeClass結構和一系列神秘的宏實現的。而動態創建技術 的前提是執行期類型識別網的建立。下面就讓我們來看看執行期類型識別網是如何建立起來的?
                                   ///////////////////////////////////////////////////
                                   /*一. 1.CRuntimeClass結構總覽 */
                                   ///////////////////////////////////////////////////
               注釋:CRuntimeClass結構定義在..\Visual Studio.NET\vc7\atlmfc\include\Afx.h中
            // object type information  
            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
            #ifdef _AFXDLL
             CRuntimeClass* (PASCAL* m_pfnGetBaseClass)();
            #else
             CRuntimeClass* m_pBaseClass;
            #endif
            // Operations
             CObject* CreateObject();
             BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const;

             // dynamic name lookup and creation
             static CRuntimeClass* PASCAL FromName(LPCSTR lpszClassName);//for ANSI
             static CRuntimeClass* PASCAL FromName(LPCWSTR lpszClassName);//for Unicode
             static CObject* PASCAL CreateObject(LPCSTR lpszClassName);  for ANSI
             static CObject* PASCAL CreateObject(LPCWSTR lpszClassName);//for Unicode
            // Implementation
             void Store(CArchive& ar) const;
             static CRuntimeClass* PASCAL Load(CArchive& ar, UINT* pwSchemaNum);
                   
                   // CRuntimeClass objects linked together in simple list
             CRuntimeClass* m_pNextClass;       // linked list of registered classes
             const AFX_CLASSINIT* m_pClassInit;
            };

                                   /////////////////////////////////////////////////////////
                                   /* 一.2.執行期類型識別網組成部分 */
                                   //////////////////////////////////////////////////////////
              在CRuntimeClass結構中與執行期類型識別網建立有關的成員如下:
              struct CRuntimeClass
              { 
                  ...//
                  LPCSTR m_lpszClassName;
                  CRuntimeClass* m_pBaseClass;
                        
               }

             
                                   //////////////////////////////////////////////////////////
                                   /*一.3.執行期類型識別網的連接建立*/
                                   //////////////////////////////////////////////////////////
               MFC在每一個具有執行期類型識別能力的類的.h和.cpp文件中都添加了兩個宏。他們是:
            //in xx.h
              class class_name
              {
                  DECLARE_DYNAMIC(class_name)
                  ...//
              }
            //in xx.cpp
              IMPLEMENT_DYNAMIC(class_name, base_class_name)
              ...//
              這兩個宏展開后是什么樣子呢?讓我們看看其源代碼吧!
              注釋:這兩個宏定義在..\Visual Studio.NET\vc7\atlmfc\include\Afx.h中
             
              #define DECLARE_DYNAMIC(class_name) \
              public: \
             static const CRuntimeClass class##class_name; \
             virtual CRuntimeClass* GetRuntimeClass() const; \


              #define IMPLEMENT_DYNAMIC(class_name, base_class_name) \
             IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL, NULL)

             
              #define IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew, class_init) \
              AFX_COMDAT const CRuntimeClass class_name::class##class_name = { \
              #class_name, sizeof(class class_name), wSchema, pfnNew, \
               RUNTIME_CLASS(base_class_name), NULL, class_init }; \
              CRuntimeClass* class_name::GetRuntimeClass() const \
              { return RUNTIME_CLASS(class_name); } \
              相關宏定義如下:
              #define RUNTIME_CLASS(class_name) _RUNTIME_CLASS(class_name)
              #define _RUNTIME_CLASS(class_name) ((CRuntimeClass*)(&class_name::class##class_name))
             
              看清了吧!這兩個宏互相配合著在每個類中都塞進了點東東,至于什么東東,自己看唄兒!
             
              下面我以一個具體的類來展示以下執行期類型識別網是如何連接建立的。
              以一個MDI應用程序的CMainFrame類為例:
              //in MaimFrm.h
              class CMainFrame : public CMDIFrameWnd
             {
             DECLARE_DYNAMIC(CMainFrame)
                     ...//
             }

              //in MaimFrm.cpp
              IMPLEMENT_DYNAMIC(CMainFrame, CMDIFrameWnd)
              ...//

              展開后得:
              //in MaimFrm.h
              class CMainFrame : public CMDIFrameWnd
             {
              public:
             static const CRuntimeClass classCMainFrame;
             virtual CRuntimeClass* GetRuntimeClass() const;
                ...//
             }

              //in MaimFrm.cpp
             
              AFX_COMDAT const CRuntimeClass CMainFrame::classCMainFrame ={CMainFrame,sizeof(classCMainFrame  ),0xFFFF,NULL,(CRuntimeClass*)(&CMDIFrameWnd::classCMDIFrameWnd),NULL,NULL};

              CRuntimeClass* CMainFrame::GetRuntimeClass() const
              { return &CMainFrame::classCMainFrame; }
              有上面的代碼可以看到IMPLEMENT_DYNAMIC宏初始化和實現了DECLARE_DYNAMIC宏為CMainFrame添加的CRuntimeClass classCMainFrame和CRuntimeClass* GetRuntimeClass() const靜態函數。
            其中最重要的一點是:   CMainFrame類的classCMainFrame對象的CRuntimeClass* m_pBaseClass被“間接的”賦值為&CMDIFrameWnd::classCMDIFrameWnd,也就是它基類的靜態CRuntimeClass classCMDIFrameWnd成員。
            以此類推一:
               CMDIFrameWnd::classCMDIFrameWnd的成員CRuntimeClass* m_pBaseClass被“間接的”賦值為
            其基類&CFrameWnd::classCFrameWnd;
               ....
               ....
               CCmdTarget::classCCmdTarget的成員CRuntimeClass* m_pBaseClass被“間接的”賦值為&CObject::classCObject;
               CObject沒有基類,那么CObject::classCObject的成員CRuntimeClass* m_pBaseClass被賦予什么值呢?看看what is the special runtime-class structure for CObject (no base class) in MFC Framework?

              注釋:CMainFrame類的基類順序以此是CMDIFrameWnd--〉CFrameWnd-->CWnd-->CCmdTarget-->CObject

            //in Afx.h
            // class CObject is the root of all compliant objects
             class AFX_NOVTABLE CObject
             {
               public:
               virtual CRuntimeClass* GetRuntimeClass() const;
               static const CRuntimeClass classCObject;
               ...//
             }
             
            //in objcore.cpp
             // special runtime-class structure for CObject (no base class)
             const struct CRuntimeClass CObject::classCObject =
             { "CObject", sizeof(CObject), 0xffff, NULL, NULL, NULL };

             CRuntimeClass* CObject::GetRuntimeClass() const
             {
             return _RUNTIME_CLASS(CObject);
             }
             
                                   ///////////////////////////////////////////////////////
                                   /* 一.4.執行期類型識別網的應用 */
                                   //////////////////////////////////////////////////////
                執行期類型識別網建立好了,它將在MFC Framework中發揮重要作用,這里舉一個其應用的例子:
                CObject::IsKindOf函數就是利用該網完成的函數。下面看看其源代碼:
              //in objcore.cpp
              BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const
              {
             ASSERT(this != NULL);
             // it better be in valid memory, at least for CObject size
             ASSERT(AfxIsValidAddress(this, sizeof(CObject)));
                    // simple SI case
             CRuntimeClass* pClassThis = GetRuntimeClass();
             return pClassThis->IsDerivedFrom(pClass);
              }
              BOOL CRuntimeClass::IsDerivedFrom(const CRuntimeClass* pBaseClass) const
             {
             ASSERT(this != NULL);
             ASSERT(AfxIsValidAddress(this, sizeof(CRuntimeClass), FALSE));
             ASSERT(pBaseClass != NULL);
             ASSERT(AfxIsValidAddress(pBaseClass, sizeof(CRuntimeClass), FALSE));

             // simple SI case
             const CRuntimeClass* pClassThis = this;
               #ifdef _AFXDLL
             for (;;)
               #else
             while (pClassThis != NULL)
               #endif
             {
              if (pClassThis == pBaseClass)
               return TRUE;
               #ifdef _AFXDLL
              if (pClassThis->m_pfnGetBaseClass == NULL)
               break;
              pClassThis = (*pClassThis->m_pfnGetBaseClass)();
               #else
              pClassThis = pClassThis->m_pBaseClass;
               #endif
             }
             return FALSE;       // walked to the top, no match
            }

                                   //////////////////////////////////////////////////
                                   /*  二.1. 執行期動態創建技術   */
                                   //////////////////////////////////////////////////
               談完了執行期類型識別網建立后,就來看看另一項重要的技術-----執行期動態創建技術 ,該技術應用可謂是甚廣,在你的SDI中的主框架,視圖和其對應的文檔以及MDI中的子框架,視圖和其對應的文檔都是利用動態創建技術生成的。
               執行期動態創建技術利用的也是CRuntimeClass結構和一對對應的宏DECLARE_DYNCREATE(class_name)
            和IMPLEMENT_DYNCREATE(class_name, base_class_name);
               下面看看這兩個宏的定義吧:

               #define DECLARE_DYNCREATE(class_name) \
             DECLARE_DYNAMIC(class_name) \
             static CObject* PASCAL CreateObject();
               #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, NULL)
               應該看出來執行期類型識別網是執行期動態創建技術的基礎。
                                
                                   ///////////////////////////////////////////////////////////
                                   /* 二.2 執行期動態創建技術組成部分*/
                                   ///////////////////////////////////////////////////////////
                                  
               下面將列出與執行期動態創建技術有關的CRuntimeClass的結構成員:
                // object type information  
               struct CRuntimeClass
               {
                   CObject* (PASCAL* m_pfnCreateObject)(); // NULL => abstract class
                   CObject* CreateObject();
                   ...//
               };
              
                                   ////////////////////////////////////
                                   /*      二.3.宏展開       */
                                   ////////////////////////////////////                 
               這回我們以SDI程序中的CMainFrame的動態創建為例,下面看看上面的兩個宏在xx.h和xx.cpp文件中展開后的樣子:
               //in MainFrm.h
               class CMainFrame
               { 
                  public:
                    static const CRuntimeClass classCMainFrame;
             virtual CRuntimeClass* GetRuntimeClass() const;
                    static CObject* PASCAL CreateObject();
                    ...//
               };
               //in MainFrm.cpp
                CObject* PASCAL CMainFrame::CreateObject() { return new class_name; }
                AFX_COMDAT const CRuntimeClass CMainFrame::classCMainFrame    ={
            CMainFrame,sizeof(classCMainFrame),0xFFFF,CMainFrame::CreateObject,(CRuntimeClass*)(&CMDIFrameWnd::classCMDIFrameWnd),NULL,NULL};

                CRuntimeClass* CMainFrame::GetRuntimeClass() const
              { return &CMainFrame::classCMainFrame; }
                看出來著兩個宏展開后與前面介紹的那兩個宏的不同了吧;DECLARE_DYNCREATE在頭文件中加入了一個函數static CObject* PASCAL CreateObject();IMPLEMENT_DYNCREATE的展開也有所不同。下面將詳述。
             
             
                                     ////////////////////////////////////////////
                                     /* 二.4.如何進行動態創建  */
                                     ///////////////////////////////////////////
                讓我們看看CMainFrame的構造函數的access control吧!protected:疑惑了吧?受保護的構造函數是不能夠得實例化的。那么CMainFrame是如何被構造出來的呢?這就是微軟利用CRuntimeClass進行動態創建的原因。下面我用一個簡單的例子來詮釋一下構造方法:
               //in A.h
               class A
               {
                  protected:A(){}
                            ...//something else
                  public:static A*CreateObject();
               };
               //in A.cpp
               A*A::CreateObject()
               {  return new A();}
               //in test.cpp
               int main(void)
               {
                  A*pNewObj=A::CreateObject();//OK
                  return 0;
               }
               詮釋完了后就讓我們一一對應的看看微軟是如何做的吧,我們回頭再看看DECLARE_DYNCREATE為CMainFrame
            添加了什么吧。static CObject* PASCAL CreateObject(); 眼睛亮了吧!是的它就相當于上個例子中的 
            static A*CreateObject();那么是誰調用了它呢?再回頭看看IMPLEMENT_DYNCREATE作了什么吧?

            AFX_COMDAT const CRuntimeClass CMainFrame::classCMainFrame    ={
            CMainFrame,sizeof(classCMainFrame),0xFFFF,CMainFrame::CreateObject,(CRuntimeClass*)(&CFrameWnd::classFrameWnd),NULL,NULL};
               原來該宏把m_pfnCreateObject賦值為CMainFrame::CreateObject;
               說到這你可能還是不很清楚,那么讓我們看看MFC的代碼吧!
                CSingleDocTemplate* pDocTemplate;
             pDocTemplate = new CSingleDocTemplate(
              IDR_MAINFRAME,
              RUNTIME_CLASS(CMyDoc),
              RUNTIME_CLASS(CMainFrame),       // 主 SDI 框架窗口
              RUNTIME_CLASS(CMyView));
                我們在MFC技術內幕系列之(二)----《MFC文檔視圖結構內幕 》中曾經說過,所以這里不詳述,
                CSingleDocTemplate::OpenDocumentFile調用了CreateNewFrame
                CFrameWnd* CDocTemplate::CreateNewFrame(CDocument* pDoc, CFrameWnd* pOther)//部分源代碼
                {
             ...//
                   CFrameWnd* pFrame = (CFrameWnd*)m_pFrameClass->CreateObject();
                    ...//
                }
                m_pFrameClass是CRuntimeClass*指針它指向CMainFrame::classCMainFrame;CreateNewFrame函數調用了
            (CFrameWnd*)m_pFrameClass->CreateObject();而CObject* CRuntimeClass::CreateObject()代碼如下:
                              
              //in objcore.cpp
              CObject* CRuntimeClass::CreateObject()
             {
             if (m_pfnCreateObject == NULL)
             {
              TRACE(traceAppMsg, 0,
               _T("Error: Trying to create object which is not ")
               _T("DECLARE_DYNCREATE \nor DECLARE_SERIAL: %hs.\n"),
               m_lpszClassName);
              return NULL;
             }

             CObject* pObject = NULL;
             TRY
             {
              pObject = (*m_pfnCreateObject)();
             }
             END_TRY

             return pObject;
             }
              它調用了 (*m_pfnCreateObject)();即 CMainFrame::CreateObject();并返回了動態創建的 CMainFrame對象的指針。看到著你應該明白了吧。    
                                   /////////////////////////////////////////
                                   /*        三.下期預告         */
                                   /////////////////////////////////////////
               MFC技術內幕系列之(四)-----《MFC消息映射與消息傳遞內幕》

            posted on 2007-07-27 11:30 醒目西西 閱讀(642) 評論(0)  編輯 收藏 引用
            久久综合丁香激情久久| 伊人久久大香线蕉亚洲五月天 | 9久久9久久精品| 伊人久久大香线焦综合四虎| 99久久精品免费看国产| 久久精品国产99久久丝袜 | 欧美黑人激情性久久| 丁香狠狠色婷婷久久综合| 香蕉aa三级久久毛片| 国内精品九九久久久精品| 久久久久国产视频电影| 精品国产VA久久久久久久冰| 亚洲精品国产自在久久| 国产精品久久久久aaaa| 久久久久人妻一区二区三区| 99国内精品久久久久久久| 麻豆一区二区99久久久久| 人妻丰满?V无码久久不卡| 久久综合综合久久狠狠狠97色88| 超级碰碰碰碰97久久久久| 久久性生大片免费观看性| 一级做a爱片久久毛片| 日韩精品久久无码人妻中文字幕| 久久久亚洲精品蜜桃臀| 久久免费高清视频| 久久精品麻豆日日躁夜夜躁| 久久久久亚洲国产| 模特私拍国产精品久久| 国产999精品久久久久久| 波多野结衣中文字幕久久| 99蜜桃臀久久久欧美精品网站| 亚洲国产成人精品无码久久久久久综合 | 久久精品日日躁夜夜躁欧美| 中文字幕无码久久久| 亚洲国产小视频精品久久久三级 | 精品久久久久久亚洲| 蜜臀久久99精品久久久久久小说| 亚洲成色www久久网站夜月| 亚洲午夜久久久久妓女影院 | 少妇精品久久久一区二区三区| 亚洲人AV永久一区二区三区久久|