日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

MFC六大核心机制之三:动态创建

發布時間:2024/4/11 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MFC六大核心机制之三:动态创建 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

MFC中很多地方都使用了動態創建技術。動態創建就是在程序運行時創建指定類的對象。例如MFC的單文檔程序中,文檔模板類的對象就動態創建了框架窗口對象、文檔對象和視圖對象。動態創建技術對于希望了解MFC底層運行機制的朋友來說,非常有必要弄清楚。

???????不需要手動實例化對象的疑惑

?????? MFC編程入門時,一般人都會有這樣的疑惑:MFC中幾個主要的類不需要我們設計也就罷了,為什么連實例化對象都不用我們來做?我們認為本該是:需要框架的時候,親手寫上CFrameWnd myFrame;需要視的時候,親自打上CView myView;……。

?????? 但MFC不給我們這個機會,致使我們錯覺窗口沒有實例化就彈出來了!但大伙想了一下,可能會一拍腦門,認為簡單不過:MFC自動幫我們完成CView myView之流的代碼不就行了么!其實不然,寫MFC程序的時候,我們幾乎要對每個大類進行派生改寫。換句話說,MFC并不知道我們打算怎樣去改寫這些類,當然也不打算全部為我們“靜態”創建這些類了。即使靜態了創建這些類也沒有用,因為我們從來也不會直接利用這些類的實例干什么事情。我們只知道,想做什么事情就往各大類里塞,不管什么變量、方法照塞,塞完之后,我們似乎并未實例化對象,程序就可以運行!

???????CRuntimeClass鏈表

???????要做到把自己的類交給MFC,MFC就用同一樣的方法,把不同的類一一準確創建,我們要做些什么事情呢?同樣地,我們要建立鏈表,記錄各類的關鍵信息,在動態創建的時候找出這些信息,就象上一節RTTI那樣!我們可以設計一個類:

C++代碼
  • struct?CRuntimeClass{ ??
  • ???????LPCSTR?m_lpszClassName;????????????????//類名指針???
  • ???????CObject*?(PASCAL?*m_pfnCreateObject)();???//創建對象的函數的指針??
  • ???????CRuntimeClass*?m_pBaseClass;?????????????????????????//講RTTI時介紹過???
  • ???????CRuntimeClass*?m_pNextClass;????????????//指向鏈表的下一個元素(許多朋友說上一節講RTTI時并沒有用到這個指針,我原本以為這樣更好理解一些,因為沒有這個指針,這個鏈表是無法連起來,而m_pBaseClass僅僅是向基類走,在MFC的樹型層次結構中m_pBaseClass是不能遍歷的)???
  • ???????CObject*?CreateObject();?????????????????//創建對象???
  • ???????static?CRuntimeClass*?PASCAL?Load();????//遍歷整個類型鏈表,返回符合動態創建的對象。???
  • ???????static?CRuntimeClass*?pFirstClass;????????//類型鏈表的頭指針????
  • };??
  • ??????一下子往結構里面塞了那么多的東西,大家可以覺得有點頭暈。至于CObject* (PASCAL *m_pfnCreateObject)();,這定義函數指針的方法,大家可能有點陌生。函數指針在C++書籍里一般被定為選學章節,但MFC還是經常用到此類的函數,比如我們所熟悉的回調函數。簡單地說m_pfnCreateObject即是保存了一個函數的地址,它將會創建一個對象。即是說,以后,m_pfnCreateObject指向不同的函數,我們就會創建不同類型的對象。

    ??????有函數指針,我們要實現一個與原定義參數及返回值都相同一個函數,在MFC中定義為:

    ????? static CObject* PASCAL CreateObject(){return new XXX};//XXX為類名。類名不同,我們就創建不同的對象。

    ??????由此,我們可以如下構造CRuntimeClass到鏈表(偽代碼):

    ?????? CRuntimeClass classXXX={???
    ?????? 類名,???
    ?????? ……,???
    ?????? XXX::CreateObject(),? //m_pfnCreateObject指向的函數???
    ?????? RUNTIME_CLASS(基類名), // RUNTIME_CLASS宏可以返回CRuntimeClass對象指針。???
    ?????? NULL?????????????????? //m_pNextClass暫時為空,最后會我們再設法讓它指向舊鏈表表頭。???
    ?????? };

    ?????? 這樣,我們用函數指針m_pfnCreateObject(指向CreateObject函數),就隨時可new新對象了。并且大家留意到,我們在設計CRuntimeClass類對時候,只有類名(和基類名)的不同(我們用XXX代替的地方),其它的地方一樣,這正是我們想要的,因為我們動態創建也象RTTI那樣用到兩個宏,只要傳入類名和基類作宏參數,就可以滿足條件。

    ?????? 即是說,我們類說明中使用DECLARE_DYNCREATE(CLASSNMAE)宏和在類的實現文件中使用IMPLEMENT_DYNCREATE(CLASSNAME,BASECLASS)宏來為我們加入鏈表,至于這兩個宏怎么為我們建立一個鏈表,我們自己可以玩玩文字代換的游戲,在此不一一累贅。但要說明的一點就是:動態創建宏xxx_DYNCREATE包含了RTTI宏,即是說, xxx_DYNCREATE是xxx_DYNAMIC的“增強版”。

    ?????? 到此,我們有必要了解一下上節課沒有明講的m_pNextClass指針。因為MFC層次結構是樹狀的,并不是直線的。如果我們只有一個m_pBaseClass指針,它只會沿著基類上去,會漏掉其它分支。在動態創建時,必需要檢查整個鏈表,看有多少個要動態創建的對象,即是說要從表頭(pFirstClass)開始一直遍歷到表尾(m_pNextClass=NULL),不能漏掉一個CRuntimeClass對象。

    ?????? 所以每當有一個新的鏈表元素要加入鏈表的時候,我們要做的就是使新的鏈表元素成為表頭,并且m_pNextClass指向原來鏈表的表頭,即像下面那樣(當然,這些不需要我們操心,是RTTI宏幫助我們完成的):

    C++代碼
  • pNewClass->m_pNextClass=CRuntimeClass::pFirstClass;//新元素的m_pNextClass指針指向想加入的鏈表的表頭。???
  • CRuntimeClass::pFirstClass=pNewClass;//鏈表的頭指針指向剛插入的新元素。??
  • ?????? 好了,有了上面的鏈表,我們就可以分析動態創建了。

    ???????動態創建的步驟

    ?????? 有了一個包含類名,函數指針,動態創建函數的鏈表,我們就可以知道應該按什么步驟去動態創建了:

    ?????? 1、獲得一要動態創建的類的類名(假設為A)。

    ?????? 2、將A跟鏈表里面每個元素的m_lpszClassName指向的類名作比較。

    ???????3、若找到跟A相同的類名就返回A所屬的CRuntimeClass元素的指針。

    ?????? 4、判斷m_pfnCreateObject是否有指向創建函數,有則創建對象,并返回該對象。

    ???????代碼演示如下(以下兩個函數都是CRuntimeClass類函數):

    C++代碼
  • ///以下為根據類名從表頭向表尾查找所屬的CRuntimeClass對象???
  • ??
  • CRuntimeClass*?PASCAL?CRuntimeClass::Load() ??
  • { ??
  • char?szClassXXX[64]; ??
  • CRuntimeClass*?pClass; ??
  • cin>>szClassXXX;??????//假定這是我們希望動態創建的類名???
  • for(pClass=pFirstClass;pClass!=NULL;pClass=pClass->m_pNextClass) ??
  • { ??
  • ?????if(strcmp(szClassXXX,pClass->m_lpszClassName)==0) ??
  • ?????return?pClass; ??
  • } ??
  • ?????return?NULL; ??
  • } ??
  • ??
  • ///根據CRuntimeClass創建對象///???
  • CObject*?CRuntimeClass::CreateObject() ??
  • { ??
  • ?????if(m_pfnCreateObject==NULL)?return?NULL; ??
  • ?????CObject?*pObject; ??
  • ?????pObject=(*?m_pfnCreateObject)();??????????????//函數指針調用???
  • ?????return?pObject;??????????????????????????????????? ??
  • }??
  • ?????? 有了上面兩個函數,我們在程序執行的時候調用,就可以動態創建對象了。

    ???????簡單實現動態創建

    ?????? 我們還可以更簡單地實現動態創建,大家注意到,就是在我們的程序類里面有一個RUNTIME_CLASS(class_name)宏,這個宏在MFC里定義為:

    ?????? RUNTIME_CLASS(class_name)? ((CRuntimeClass*)(&class_name::class##class_name))

    ???????作用就是得到類的RunTime信息,即返回class_name所屬CRuntimeClass的對象。在我們的應用程序類(CMyWinApp)的InitInstance()函數下面的CSingleDocTemplate函數中,有:

    ?????? RUNTIME_CLASS(CMyDoc),

    ???????RUNTIME_CLASS(CMainFrame),?????? // main SDI frame window

    ???????RUNTIME_CLASS(CMyView)

    ?????? 構造文檔模板的時候就用這個宏得到文檔、框架和視的RunTime信息。有了RunTime信息,我們只要一條語句就可以動態創建了,如:

    ???????classMyView->CreateObject();????? //對象直接調用用CRuntimeClass本身的CreateObject()

    ???????總結

    ?????? 最后再總結和明確下動態創建的具體步驟:

    ?????? 1、定義一個不帶參數的構造函數(默認構造函數);因為我們是用CreateObject()動態創建,它只有一條語句就是return new XXX,不帶任何參數。所以我們要有一個無參構造函數。

    ?????? 2、類說明中使用DECLARE_DYNCREATE(CLASSNMAE)宏;和在類的實現文件中使用IMPLEMENT_DYNCREATE(CLASSNAME,BASECLASS)宏;這個宏完成構造CRuntimeClass對象,并加入到鏈表中。

    ?????? 3、使用時先通過宏RUNTIME_CLASS得到類的RunTime信息,然后使用CRuntimeClass的成員函數CreateObject創建一個該類的實例。

    ?????? 4、CObject* pObject = pRuntimeClass->CreateObject();//完成動態創建。

    總結

    以上是生活随笔為你收集整理的MFC六大核心机制之三:动态创建的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。