首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

MFC六大關鍵技術深度剖析:動態建立機制完整解讀

     編輯:關於C語言

一、為何需要動態建立?

MFC文檔/視圖架構中,框架視窗、視圖、文檔等核心物件皆由文檔模板動態建立。初學者常困惑:「明明沒寫CFrameWnd myFrame;,視窗怎麼彈出來的?」

關鍵在於:MFC不知道開發者會如何衍生這些類別,無法靜態實例化。必須在執行期根據衍生類別資訊動態創建對應物件。

二、核心資料結構:CRuntimeClass


struct CRuntimeClass {
    LPCSTR m_lpszClassName;                    // 類別名稱
    CObject* (PASCAL *m_pfnCreateObject)();    // 建立物件的函數指標
    CRuntimeClass* m_pBaseClass;               // 基類別RuntimeClass (支援RTTI)
    CRuntimeClass* m_pNextClass;               // 單向鏈表指標 (遍歷所有動態類別)
    
    CObject* CreateObject();                   // 呼叫m_pfnCreateObject建立物件
    static CRuntimeClass* PASCAL Load();       // 依類別名稱查找鏈表
    static CRuntimeClass* pFirstClass;         // 鏈表頭指標
};

m_pfnCreateObject指向靜態函數CreateObject(),回傳new DerivedClass。每個衍生類別擁有獨立的CRuntimeClass實例,透過m_pNextClass串成單向鏈表。

三、鏈表建立與宏機制

兩大宏

  • DECLARE_DYNCREATE(ClassName):類別宣告中使用,宣告靜態CRuntimeClass成員與CreateObject
  • IMPLEMENT_DYNCREATE(ClassName, BaseClass):實作檔中使用,定義CRuntimeClass實例並插入鏈表頭

插入鏈表邏輯 (IMPLEMENT_DYNCREATE展開)


// 簡化版邏輯
CRuntimeClass* pNewClass = &ClassName::classClassName;  // 靜態實例
pNewClass->m_pNextClass = CRuntimeClass::pFirstClass;   // 新節點指向舊頭
CRuntimeClass::pFirstClass = pNewClass;                 // 更新頭指標

註:DYNCREATE宏包含DYNAMIC (RTTI) 功能,為增強版。

四、動態建立完整流程

  1. 取得欲建立類別的名稱 (字串)
  2. 從pFirstClass遍歷鏈表,strcmp比對m_lpszClassName
  3. 找到對應CRuntimeClass*
  4. 檢查m_pfnCreateObject != NULL
  5. 呼叫(*m_pfnCreateObject)()建立物件,回傳CObject*

核心函數實作


// 查找類別
CRuntimeClass* PASCAL CRuntimeClass::Load() {
    char szClass[64];
    cin >> szClass;  // 假設取得類別名稱
    for (CRuntimeClass* p = pFirstClass; p; p = p->m_pNextClass) {
        if (strcmp(szClass, p->m_lpszClassName) == 0) return p;
    }
    return NULL;
}

// 建立物件
CObject* CRuntimeClass::CreateObject() {
    if (!m_pfnCreateObject) return NULL;
    return (*m_pfnCreateObject)();  // 函數指標呼叫
}

五、應用層使用方式

1. 文檔模板建構時


CSingleDocTemplate(
    IDR_MAINFRAME,
    RUNTIME_CLASS(CMyDoc),      // 取得CRuntimeClass*
    RUNTIME_CLASS(CMainFrame),
    RUNTIME_CLASS(CMyView)
);

RUNTIME_CLASS(ClassName)宏展開為((CRuntimeClass*)(&ClassName::classClassName)),直接取得靜態實例位址。

2. 直接動態建立


CRuntimeClass* pClass = RUNTIME_CLASS(CMyView);
CObject* pObj = pClass->CreateObject();  // 動態建立CMyView實例
CMyView* pView = static_cast(pObj);

六、開發者必須滿足的四個條件

  1. 預設建構函數:CreateObject內部new ClassName()不帶參數
  2. DECLARE_DYNCREATE:類別宣告處
  3. IMPLEMENT_DYNCREATE:實作檔,指定基類別
  4. 使用RUNTIME_CLASS + CreateObject:執行期建立

七、為何需要m_pNextClass而非僅靠m_pBaseClass?

MFC類別階層是樹狀結構。m_pBaseClass僅向上追溯基類別,無法遍歷同層或其他分支。動態建立需掃描所有註冊類別,故必須有單向鏈表m_pNextClass連接所有CRuntimeClass節點,從pFirstClass遍歷至尾端 (NULL)。

總結

MFC動態建立機制核心在於:CRuntimeClass單向鏈表 + 函數指標工廠模式 + 雙宏註冊。將類別中繼資料 (名稱、建立函數、繼承關係) 登記在全域鏈表,執行期透過名稱查找並呼叫對應工廠函數實例化。這種設計完美解決「框架不知衍生類別細節」的逆向控制問題,是MFC文檔/視圖架構運作的基石。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved