




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、MF6大關(guān)鍵技術(shù)一題外話:我并不認(rèn)為MFC®輕了程序員們的負(fù)擔(dān),MFCB現(xiàn)的目的雖然似乎是為了讓程序 員不用懂得太多就可以進(jìn)行視窗編程,但本人在MFCS徘徊了很久很久由于那 時(shí)沒(méi)有書本詳細(xì)介紹MFC勺原理,毫無(wú)收獲.可能朋友們會(huì)說(shuō),怎么一定要了 解MFC勺具體呢,“黑箱作業(yè)不行嗎?這不是微軟的初衷嗎?不行! ! !如果這樣,我寧愿永遠(yuǎn)不選擇 MFC在學(xué)電腦之前,本人學(xué)習(xí)的東西 大都與藝術(shù)不無(wú)關(guān)系,小學(xué)時(shí)參加過(guò)全國(guó)書畫比賽獲銀獎(jiǎng). 兒時(shí)的愛好就是在一 張紙上隨心所欲地畫畫! MFC“黑箱就象一幅碩大的抽象畫抽象到你不能理 解,它用鉛筆勾畫好線條,然后請(qǐng)你填顏色.我們?cè)趺茨苋淌堋昂谙渥鳂I(yè)
2、?我們選擇 C+,就是由于它夠自由,夠藝術(shù),我們可以在此放飛夢(mèng)想.所以,我們要攻克 MFC偉大孫老師在剖析MFC勺時(shí)候雖然盡心盡力,但可能由于篇幅所限,說(shuō)得并不大 清楚我相信許多學(xué)員都有這方面的感受.在此,我突發(fā)奇想,想與大家一同 分享一下著名的MF6大關(guān)鍵技術(shù).從什么地方開始講起好呢?我覺(jué)得回到最初摸索 MFC勺時(shí)候,從根本談起最好.由于我知道,一個(gè)走過(guò)來(lái)程序員,總是忘記了當(dāng)初自己是怎么走過(guò)來(lái)的, 忘記了 一個(gè)學(xué)員最想知道的是什么.一個(gè)小小的問(wèn)題一兩句話就可以解釋的,足學(xué) 以令手無(wú)寸鐵的學(xué)員頭大半個(gè)月, 所以,我努力回憶當(dāng)初是怎么讓自己豁然開朗 的.轉(zhuǎn)入正題:MFC勺六大關(guān)鍵技術(shù)包括:MFC
3、S序的初始化過(guò)程.運(yùn)行時(shí)類型識(shí)別RTTI.動(dòng)態(tài)創(chuàng)立.永久保存.消息映射.消息傳遞.MFCS序的初始化過(guò)程1、設(shè)計(jì)一個(gè)簡(jiǎn)單完整MFCS序,產(chǎn)生一個(gè)窗口.當(dāng)然這不能讓 AppWizard自動(dòng) 為我們生成.我們可以在Win32 Application 工程下面那樣寫:#include <afxwin.h>class MyApp : public CWinApppublic:BOOL InitInstance / 程序入點(diǎn)CFrameWnd *Frame=new CFrameWnd;/構(gòu)造框架m_pMainWnd=Frame; /將 m_pMainWndi定為 Frame;Frame-&g
4、t;CreateNULL,"最簡(jiǎn)單的窗口 "/ 建立框架Frame->ShowWindowSW_SHOW; / 顯示框架 return true;/ 返回;MyApp theApp;/建立應(yīng)用程序.設(shè)定鏈接MFCW,運(yùn)行,即可看見一個(gè)窗口.從上面,大家可以看到建立一個(gè) MFCS 口很容易,只用兩步:一是從 CWinApp 派生一個(gè)應(yīng)用程序類這里是 MyApp ,然后建立應(yīng)用程序?qū)ο髏heApp, 就可以產(chǎn)生一個(gè)自己需要的窗口 即需要什么樣就在InitInstance 里創(chuàng)立就 行了.整個(gè)程序,就改寫一個(gè)InitInstance 函數(shù),創(chuàng)立那么一個(gè)對(duì)象theApp,就
5、是一個(gè)完整的窗口程序.這就是“黑箱作業(yè)的魅力! ! ! !在我們正想為微軟鼓掌的時(shí)候,我們忽然覺(jué)得心里空蕩蕩的,我們想知道微軟幫 我們做了什么事情,而我們想編自己的程序時(shí)又需要做什么事情,那怕在上面幾行的程序里面,我們還有不清楚的地方,比方,干嘛有一個(gè)m_pMainWn始針變量,它從哪里來(lái),又要到哪里去呢?想一想在 DOST編程是多么吳妙的一件事呵, 我們需要什么變量,就聲明什么變量,需要什么樣的函數(shù),就編寫什么樣的函數(shù), 或者引用函數(shù)庫(kù)但是現(xiàn)在我們?cè)趺崔k! ! !我們可以逆向思維一下,MFCS到達(dá)這種效果,它是怎么做的呢?首先我們要弄 明白,VC不是一種語(yǔ)言,它就象我們學(xué) c語(yǔ)言的時(shí)候的一個(gè)
6、類似記事本的編輯 器請(qǐng)?jiān)徫业牟毁N切的比喻,所以,在 VC里面我們用的是C+郵言編程, C+材是根本初學(xué)者總是以為VC是一門什么新的什么語(yǔ)言,一門比 C+銃進(jìn)很 多的復(fù)雜語(yǔ)言,汗.說(shuō)了那么多,我想用一句簡(jiǎn)單的話概括“MFC'黑箱就是幫助我們插入了 C+弋碼的東西.既然MFC1箱幫我們插入了代碼,那么大家想想它會(huì)幫我們插入什么樣的代碼呢?他會(huì)幫我們插入求解一元二次方程的代碼嗎?當(dāng)然不會(huì),所以它插入的實(shí)際上是每次編寫窗口程序必須的,通用的代碼.再往下想,什么才是通用的呢?我們每次視窗編程都要寫WinMain函數(shù),都要有注冊(cè)窗口,產(chǎn)生窗口,消息循環(huán),回調(diào)函數(shù)即然每次都要的東西,就讓它 們從我
7、們眼前消失,讓 MFO忙寫入!要知道MFC0始化過(guò)程,大家當(dāng)然可以跟蹤執(zhí)行程序.孫老師的第三課跟蹤了很 長(zhǎng)一段時(shí)間,我相信大家都有點(diǎn)暈頭轉(zhuǎn)向.本人覺(jué)得那怕你理解了 MFC弋碼,也 很容易讓人找不著北,我們完全不懂的時(shí)候,在成千上萬(wàn)行程序的迷宮中如何能 找到出口?我們要換一種方法,不如就來(lái)重新編寫個(gè) MFC!吧,嘩!大家不要笑,小心你的 大牙,我不是瘋子雖然瘋子也說(shuō)自己不瘋.我們要寫的就是最簡(jiǎn)單的MFC類庫(kù),就是把MF砥觀上的,理論上的東西寫出來(lái).我們要用最簡(jiǎn)化的代碼,簡(jiǎn) 化到剛好能運(yùn)行.既然,我們這一節(jié)寫的是MFCS序的初始化過(guò)程,上面我們還有了一個(gè)可執(zhí)行的 MFCS序.程序中只是用了兩個(gè) M
8、FCS, 一個(gè)是 CWinApp另一個(gè)是CFrameWnd 當(dāng)然,還有很多同樣重要MFC!如視圖類,文檔類等等.但在上面的程序可以不用到,所以暫時(shí)省去了它(總之是為了簡(jiǎn)單) 好,現(xiàn)在開始寫MF廢庫(kù)吧唉,面前又有一個(gè)大難題,就是讓大家背一下 MFC1次結(jié)構(gòu)圖.天,那張魚網(wǎng)怎么記得住,但既然我們要理解他,總得知道它 是從那里派生出來(lái)的吧.考慮到大家都很辛苦,那我們看一下上面兩個(gè)類的父子關(guān)系(箭頭代表派生廣CObject->CCmdTarget->CWinThread->CWinApp->§ 己的重寫了 InitInstance() 的應(yīng)用程序類.CObject (
9、同上)->CCmdTarget (同上)->CWnd->CFrameWnd看到層次關(guān)系圖之后,終于可以開始寫MF暖庫(kù)了.根據(jù)上面層次結(jié)構(gòu),我們可 以寫以下六個(gè)類(為了直觀,省去了構(gòu)造函數(shù)和析構(gòu)函數(shù))./class CObiect;/MFC 類的基類.class CCmdTarget : public CObject;class CWinThread : public CCmdTarget;class CWinApp : public CWinThread;class CWnd : public CCmdTarget; class CFrameWnd : public CWnd
10、; /大家再想一下,在上面的類里面,應(yīng)該有什么?大家馬上會(huì)想到,CWinAp瞇或者它的基類 CCmdTarget里面應(yīng)該有一個(gè)虛函數(shù) virtual BOOL InitInstance(), 是的,由于那里是程序的入口點(diǎn),初始化程序的地方,那自然少不了的.可能有 些朋友會(huì)說(shuō),反正InitInstance()在派生類中一定要重載,我不在 CCmdTarget或CWinAp冰里定義,留待CWinAp由勺派生類去增加這個(gè)函數(shù)可不可以.扯到這個(gè)問(wèn)題可能有點(diǎn)越說(shuō)越遠(yuǎn),但我想信C+勺朋友對(duì)虛函數(shù)應(yīng)該是沒(méi)有太多的問(wèn)題 的.總的來(lái)說(shuō),作為程序員如果清楚知道基類的某個(gè)函數(shù)要被派生類用到,那定義為虛函數(shù)要方便很多
11、.也有很多朋友問(wèn),C+包什么不自動(dòng)把基類的所有函數(shù)定義為虛函數(shù)呢,這樣可以省了很多麻煩,這樣所有函數(shù)都遵照派生類有定義的 函數(shù)就調(diào)用派生類的,沒(méi)定義的就調(diào)用基類的,不用寫virtual的麻煩多好!其 實(shí),很多面向?qū)ο蟮恼Z(yǔ)言都這樣做了.但定義一個(gè)虛函數(shù)要生成一個(gè)虛函數(shù)表, 要占用系統(tǒng)空間,虛函數(shù)越多,表就越大,有時(shí)得不償失!這里哆嗦幾句,是因 為往后要說(shuō)明的消息映射中大家更加會(huì)體驗(yàn)到這一點(diǎn),好了,就此打往.上面我們自己解決了一個(gè)問(wèn)題,就是在CCmdTarget一個(gè)virtual BOOLInitInstance() .大家再下想,我們還要我們 MFC“隱藏更多的東西: WinMain()函數(shù),設(shè)
12、計(jì)窗 口類,窗口注冊(cè),消息循環(huán),回調(diào)函數(shù)我們馬上想到封裝想封裝他們.大家 似乎隱約地感覺(jué)到封裝 WinMain()不容易,覺(jué)得WinMain()是一個(gè)特殊的函數(shù), 許多時(shí)候它代表了一個(gè)程序的起始和終結(jié).所以在以前寫程序的時(shí)候,我們寫程序習(xí)慣從WinMain()的左大括寫起,到右大括弧返回、結(jié)束程序.我們換一個(gè)角度去想,有什么東西可以拿到 WinMain()外面去做,許多初學(xué)者們, 總覺(jué)得WinMain()函數(shù)天大的函數(shù),什么函數(shù)都好象要在它里面才能真正運(yùn)行.其實(shí)這樣了解很片面,甚至錯(cuò)誤.我們可以寫一個(gè)這樣的C+取序:/#include <iostream.h>class testp
13、ublic:test()cout<<" 請(qǐng)改變你對(duì)main()函數(shù)的看法! "<<endl;test test1;/*/void main()/在上面的程序里,入口的 main()函數(shù)外表上什么也不做,但程序執(zhí)行了(注: 實(shí)際入口函數(shù)做了一些我們可以不了解的事情),并輸出了一句話(注:全局對(duì) 象比main()首先運(yùn)行).現(xiàn)在大家可以知道我們的 WinMain()函數(shù)可以什么都不 做,程序依然可以運(yùn)行,但沒(méi)有這個(gè)入口函數(shù)程序會(huì)報(bào)錯(cuò).那么WinMain()函數(shù)會(huì)放哪個(gè)類上面呢,請(qǐng)看下面程序:#include <afxwin.h>class M
14、yApp : public CWinApppublic:BOOL InitInstance() / 程序入點(diǎn)AfxMessageBox("程序依然可以運(yùn)行!");return true; ;MyApp theApp;/建立應(yīng)用程序.大家可以看到,我并沒(méi)有構(gòu)造框架,而程序卻可以運(yùn)行了一一彈出一個(gè)對(duì)話框(如 果沒(méi)有WinMain()函數(shù)程序會(huì)報(bào)錯(cuò)).上面我這樣寫還是為了直觀起見,其實(shí)我 們只要寫兩行程序:#include <afxwin.h>CWinApp theApp;/整個(gè)程序只構(gòu)造一個(gè)CWinAp冰對(duì)象,任可事情,程序就可以運(yùn)行!所以說(shuō),只要我們構(gòu)造了 CWi
15、nApp寸象,就可以執(zhí)行 WinMain()函數(shù).我們馬上 相信WinMain()函數(shù)是在CWinAp瞇或它的基類中,而不是在其他類中.其實(shí)這 種看法是錯(cuò)誤的,我們知道編寫 C+附序的時(shí)候,不可能讓你在一個(gè)類中包含入 口函數(shù),WinMain()是由系統(tǒng)調(diào)用,跟我們的平時(shí)程序自身調(diào)用的函數(shù)有著本質(zhì) 的區(qū)別.我們可以暫時(shí)簡(jiǎn)單想象成,當(dāng)CWinAppX寸象構(gòu)造完的時(shí)候,WinMain()跟著執(zhí)行.現(xiàn)在大家明白了,大局部的“通用代碼(我們想封裝隱藏的東西)都可以放到CWinAp瞇中,那么它又是怎樣運(yùn)行起來(lái)的呢?為什么構(gòu)造了CWinAp冰對(duì)象就“自動(dòng)執(zhí)行那么多東西.大家再仔細(xì)想一下,CWinAp冰對(duì)象構(gòu)
16、造之后,它會(huì)“自動(dòng)執(zhí)行自己的構(gòu)造函 數(shù).那么我們可以把想要“自動(dòng)執(zhí)行的代碼放到CWinAp冰的構(gòu)造函數(shù)中.那么CWinAp冰可能打算這樣設(shè)計(jì)(先不計(jì)較正確與否): class CWinApp : public CWinThead public: virtual BOOL InitInstance();/ 解釋過(guò)的程序的入點(diǎn)CWinApp :CWinApp()/ 構(gòu)造函數(shù)/ WinMain();/這個(gè)是大家一眼看出的錯(cuò)誤Create();/設(shè)計(jì)、創(chuàng)立、更新顯示窗口Run();消息循環(huán)/ ;寫完后,大家又馬上感覺(jué)到似乎不對(duì),WinMain()函數(shù)在這里好象真的一點(diǎn)用處都沒(méi)有,并且能這樣被調(diào)用嗎(請(qǐng)
17、允許我把手按在圣經(jīng)上聲明一下:WinMain()不是普通的函數(shù),它要肩負(fù)著初始化應(yīng)用程序,包括全局變量的初始化,是由系 統(tǒng)而不是程序本身調(diào)用的,WinMain()返回之后,程序就結(jié)束了,進(jìn)程撤消). 再看Create()函數(shù),它能確定設(shè)計(jì)什么樣的窗口,創(chuàng)立什么樣的窗口嗎?如果 能在CWinApp勺構(gòu)造函數(shù)里確定的tS,我們以后設(shè)計(jì) MFCS序時(shí)窗口就一個(gè)樣, 變得寫程序變有必要.再看 Run()函數(shù),它能在 WinMain()函數(shù)外面運(yùn)行嗎?回過(guò)頭來(lái),我們可以讓 WinMain()函數(shù)一條語(yǔ)句都不包含嗎?不可以,我們看一 下WinMain()函數(shù)的四個(gè)參數(shù):WinMain(HINSTANCE,
18、 HINSTANCE, LPSTR, int)其中第一個(gè)參數(shù)指向一個(gè)實(shí)例句柄,我們?cè)谠O(shè)計(jì) WNDCLASS時(shí)候一定要指定實(shí) 例句柄.我們窗口編程,肯定要設(shè)計(jì)窗口類.所以, WinMain()再簡(jiǎn)單也要這樣 寫:int WinMain(HINSTANCE hinst, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) hInstance=hinst 既然實(shí)例句柄要等到程序開始執(zhí)行才能知道,那么我們用于創(chuàng)立窗口的Create()函數(shù)也要在 WinMain ()內(nèi)部才能執(zhí)行由于如果等到 WinMain ()執(zhí)行完畢后, 程序結(jié)束,進(jìn)程撤消
19、,當(dāng)然 Create()也不可能創(chuàng)立窗口 那么Run()(消息循環(huán))放在那里執(zhí)行好呢?眾所周知,消息循環(huán)就是相同的那么 幾何代碼,但我們也不要企圖把它放在 WinMain ()函數(shù)之外執(zhí)行.所以我們?cè)?WinMain ()函數(shù)里面,我們程序要象以下這樣寫WinMain ( 窗口類對(duì)象執(zhí)行創(chuàng)立窗口函數(shù)程序類對(duì)象執(zhí)行消息循環(huán)函數(shù))對(duì)于WinMain ()的問(wèn)題,得總結(jié)一下,我們封裝的時(shí)候是不可以把它封裝到 CWinAp瞇里面,但由于 WinMain ()的不變性(或者說(shuō)有規(guī)律可循),MFCI全有水平在我們構(gòu)造CWinAp冰對(duì)象的時(shí)候,幫我們完成那幾行代碼.轉(zhuǎn)了一個(gè)大圈,我們仿佛又回到了 SDKS程
20、的開始.但現(xiàn)在我們現(xiàn)在能清楚地知 道,外表上MFCW SDKS程截然不同,但實(shí)質(zhì)上 MFCR是用類的形式封裝了 SDK 函數(shù),封裝之后,我們?cè)?WinMain ()函數(shù)中只需要幾行代碼,就可以完成一個(gè) 窗口程序.我們也由此知道了應(yīng)如何去封裝應(yīng)用程序類( CWinApp和主框架窗 口類(CFrameWrjd.下面把上開始設(shè)計(jì)這兩個(gè)類.為了簡(jiǎn)單起見,我們忽略這兩個(gè)類的基類和派生類的編寫,可能大家會(huì)認(rèn)為這是一種很不負(fù)責(zé)任的做法,但本人覺(jué)得這既可減輕負(fù)擔(dān),又免了大家在各類之間穿 來(lái)穿去,更好理解一些(我們?cè)陉P(guān)鍵的地方作注明).還有,我把全部代碼寫在 同一個(gè)文件中,讓大家看起來(lái)不用那么吃力,但這是最不提
21、倡的寫代碼方法,大 家不要學(xué)哦! #include <windows.h>HINSTANCE hInstance;class CFrameWndHWND hwnd;public:CFrameWnd(); /也可以在這里調(diào)用Create()virtual CFrameWnd();int Create();/類就留意這一個(gè)函數(shù)就行了!BOOL ShowWnd(););class CWinApp1public:CFrameWnd* m_pMainWnd;/E真正的 MFCS面/它是CWnd旨針,但這里由于不寫 CWndfe/只要把它寫成CFrameWn指針CWinApp1* m_pCur
22、rentWinApp;/指向應(yīng)用程序?qū)ο蟊旧鞢WinApp1();virtual CWinApp1();virtual BOOL InitInstance() ;/MFC原本是必須重載的函數(shù),最重要的函 數(shù)! ! !virtual BOOL Run();/ 消息循環(huán) );CFrameWnd二CFrameWnd()CFrameWnd:CFrameWnd() int CFrameWnd:Create() / 封裝創(chuàng)立窗 口代碼 WNDCLASS wndcls;wndcls.style=0;wndcls.cbClsExtra=0;wndcls.cbWndExtra=0;wndcls.hbrBackg
23、round=(HBRUSH)GetStockObject(WHITE_BRUSH);wndcls.hCursor=LoadCursor(NULL,IDC_CROSS);wndcls.hIcon=LoadIcon(NULL,IDC_ARROW);wndcls.hInstance=hInstance;wndcls.lpfnWndProc=DefWindowProc;/ 默認(rèn)窗 口過(guò)程函數(shù)./大家可以想象成MFCS用的窗口過(guò)程.wndcls.lpszClassName="窗口類名";wndcls.lpszMenuName=NULL;RegisterClass(&wndcl
24、s);hwnd=CreateWindow("窗口類名","窗口實(shí)例標(biāo)題名,WS_OVERLAPPEDWINDOW,0,0,600,400,NULL,NULL,hInstance,NULL); return 0;BOOLCFrameWnd:ShowWnd/J 顯示更新窗口 ShowWindow(hwnd,SW_SHOWNORMAL);UpdateWindow(hwnd); return 0;/CWinApp1:CWinApp1()m_pCurrentWinApp=this;CWinApp1:-CWinApp1()/以下為InitInstance() 函數(shù),MFCt要
25、為CWinApp勺派生類改寫,/這里為了方便理解,把它放在 CWinAp冰里面完成!/你只要記住真正的MFCE派生類改寫此函數(shù)就行了.BOOLCWinApp1:InitInstance() m_pMainWnd=new CFrameWnd;m_pMainWnd->Create();m_pMainWnd->ShowWnd();return 0;BOOLCWinApp1:Run()/封裝消息循環(huán)MSG msg;while(GetMessage(&msg,NULL,0,0)TranslateMessage(&msg);DispatchMessage(&msg);r
26、eturn 0; /封裝消息循環(huán)CWinApp1 theApp; /應(yīng)用程序?qū)ο?全局)int WINAPIWinMain( HINSTANCEinst, HINSTANChPrevInstance, LPSTR lpCmdLine, int nCmdShow)hInstance=hinst;CWinApp1* pApp=theApp.m_pCurrentWinApp;/真正的MFCS寫一個(gè)全局函數(shù)AfxGetApp,以獲取CWinApp旨針.pApp->InitInstance();pApp->Run();return 0;代碼那么長(zhǎng),實(shí)際上只是寫了三個(gè)函數(shù),一是 CFrameW
27、nd的Create(),第二個(gè)是CWinAp冰的InitInstance() 和Run().在此特別要說(shuō)明的是InitInstance(),真正的MFCfr,那是我們跟據(jù)自己構(gòu)造窗口的需要,自己改寫這個(gè)函數(shù).大家可以看到,封裝了上面兩個(gè)類以后,在入口函數(shù) WinMain中就寫幾行代碼, 就可以產(chǎn)生一個(gè)窗口程序.在MFC+,由于WinMain函數(shù)就是固定的那么幾行代 碼,所以MFC色對(duì)可以幫我們自動(dòng)完成(MFC勺特長(zhǎng)就是幫我們完成有規(guī)律的代 碼),所以我們創(chuàng)造 MFCS用程序的時(shí)候,看不到 WinMain函數(shù).MF6大關(guān)鍵技術(shù)(二)運(yùn)行時(shí)類型識(shí)別(RTTI) 運(yùn)行時(shí)類型識(shí)別(RTTI)即是程序執(zhí)
28、行過(guò)程中知道某個(gè)對(duì)象屬于某個(gè)類,我們平 時(shí)用C+魏程接觸的RTTI 一般是編譯器的RTTI,即是在新版本的VC+編譯器里 面選用“使能RTTI,然后載入typeinfo.h 文件,就可以使用一個(gè)叫typeid()的運(yùn)算子,它的地位與在C+編程中的sizeof()運(yùn)算子類似的地方(包含一 個(gè)頭文件,然后就有一個(gè)熟悉好用的函數(shù)).typeid()關(guān)鍵的地方是可以接受兩 個(gè)類型的參數(shù):一個(gè)是類名稱,一個(gè)是對(duì)象指針.所以我們判別一個(gè)對(duì)象是否屬 于某個(gè)類就可以象下面那樣:if (typeid (ClassName)= typeid (*ObjectName) ) (ClassName*)ObjectNa
29、me)->Fun();象上面所說(shuō)的那樣,一個(gè)typeid ()運(yùn)算子就可以輕松地識(shí)別一個(gè)對(duì)象是否屬 于某一個(gè)類,但MFC不是用typeid ()的運(yùn)算子來(lái)進(jìn)行動(dòng)態(tài)類型識(shí)別,而是 用一大堆令人費(fèi)解的宏.很多學(xué)員在這里很迷惑,好象MFCS大局部地方都是故 作神秘.使們大家編程時(shí)很迷惘,只知道在這里參加一組宏,又在那兒參加一個(gè) 映射,而不知道我們?yōu)槭裁匆獏⒓舆@些東東.其實(shí),早期的MFC沒(méi)有typeid ()運(yùn)算子,所以只能沿用一個(gè)老方法.我們 甚至可以想象一下,如果 MFG期就有template (模板)的概念,可能更容易 解決RTTI問(wèn)題.所以,我們要回到“古老的年代,想象一下,要完成 RT
30、TI要做些什么事情.就好似我們?cè)谝粋€(gè)新型(新型到我們還不熟悉)電器公司里面,我們要識(shí)別哪個(gè) 是電飯鍋,哪個(gè)是電磁爐等等,我們要查看登記的各電器一系列的信息, 我們才 可以比擬、鑒別,那個(gè)東西是什么!要登記一系列的消息并不是一件簡(jiǎn)單的事情,大家可能首先想到用數(shù)組登記對(duì) 象.但如果用數(shù)組,我們要定義多大的數(shù)組才好呢,大了浪費(fèi)空間,小了更加不 行.所以我們要用另一種數(shù)據(jù)結(jié)構(gòu)一一 鏈表.由于鏈表理論上可大可小,可以無(wú) 限擴(kuò)展.鏈表是一種常用的數(shù)據(jù)結(jié)構(gòu),簡(jiǎn)單地說(shuō),它是在一個(gè)對(duì)象里面保存了指向下一個(gè) 同類型對(duì)象的指針.我們大體可以這樣設(shè)計(jì)我們的類:struct CRuntimeClass 類的名稱等一切信
31、息CRuntimeClass * m_pNextClass;/ 指向鏈表中下一 CRuntimeClass 對(duì)象的指針 ;鏈表還應(yīng)該有一個(gè)表頭和一個(gè)表尾,這樣我們?cè)诓殒湵碇懈鲗?duì)象元素的信息的時(shí) 候才知道從哪里查起,到哪兒結(jié)束.我們還要注明本身是由哪能個(gè)類派生.所以我們的鏈表類要這樣設(shè)計(jì):struct CRuntimeClass 類的名稱等一切信息CRuntimeClass * m_pBaseClass;/ 指向所屬的基類.CRuntimeClass * m_pNextClass;/ 定義表尾的時(shí)候只要定義此指針為空就可以了.一static CRuntimeClass* pFirstClass;
32、/這里表頭指針屬于靜態(tài)變量,由于我們 知道static變量在內(nèi)存中只初始化一次,就可以為各對(duì)象所用!保證了各對(duì)象只有一個(gè)表頭.;有了 CRuntimeClass結(jié)構(gòu)后,我們就可以定義鏈表了:static CRuntimeClass classCObject=NULL,NULL;/這里定義了一個(gè)CRuntimeClass 對(duì)象,由于 classCObject 無(wú)基類,所以 m_pBaseClass為 NULL 由于目前只有一個(gè)元素即目前沒(méi)有下一元素,所以m_pNextClass為NUL.L表 尾.至于pFirstClass 表頭,大家可能有點(diǎn)想不通,它到什么地方去了.由于我 們這里并不想把cla
33、ssCObject作為鏈表表頭,我們還要在前面插入很多的 CRuntimeClass對(duì)象,并且由于pFirstClass 為static 指針,即是說(shuō)它不是屬 于某個(gè)對(duì)象,所以我們?cè)谟盟耙瘸跏蓟篊RuntimeClass*CRuntimeClass: : pFirstClass=NULL;現(xiàn)在我們可以在前面插入一個(gè) CRuntimeClass對(duì)象,插入之前我得重要中明一 下:如果單純?yōu)榱诉\(yùn)行時(shí)類型識(shí)別,我們未必用到m_pNextClass指針更多是在運(yùn)行時(shí)創(chuàng)立時(shí)用,我們關(guān)心的是類本身和它的基類.這樣,查找一個(gè)對(duì)象是 否屬于一個(gè)類時(shí),主要關(guān)心的是類本身及它的基類,CRuntimeClas
34、s classCCmdTarget= &classCObject, NULL;CRuntimeClass classCWnd= &classCCmdTarget ,NULL ;CRuntimeClass classCView= &classCWnd , NULL ;好了,上面只是僅僅為一個(gè)指針 m_pBaseClass賦值MFCt真正CRuntimeClass 有多個(gè)成員變量和方法,就連接忘了鏈表.假設(shè)我們現(xiàn)在已全部構(gòu)造完成自己 需要的CRuntimeClass對(duì)象,那么,這時(shí)候應(yīng)該定義表頭.即要用 pFirstClass 指針指向我們最后構(gòu)造的 CRuntimeCla
35、ss 對(duì)象classCView.CRuntimeClass: : pFirstClass=&classCView;現(xiàn)在鏈表有了,表頭表尾都完善了,問(wèn)題又出現(xiàn)了,我們應(yīng)該怎樣訪問(wèn)每一個(gè) CRuntimeClass對(duì)象?要判斷一個(gè)對(duì)象屬于某類,我們要從表頭開始,一直向表 尾查找到表尾,然后才能比擬得出結(jié)果嗎.肯定不是這樣!大家可以這樣想一下,我們構(gòu)造這個(gè)鏈表的目的,就是構(gòu)造完之后,能夠按主觀 地拿一個(gè)CRuntimeClass對(duì)象和鏈表中的元素作比擬,看看其中一個(gè)對(duì)象中否屬 于你指定的類.這樣,我們需要有一個(gè)函數(shù),一個(gè)能返回自身類型名的函數(shù) GetRuntimeClass.上面簡(jiǎn)單地說(shuō)一下
36、鏈表的過(guò)程,但單純有這個(gè)鏈表是沒(méi)有任何意義.回到 MFC 中來(lái),我們要實(shí)現(xiàn)的是在每個(gè)需要有 RTTI水平的類中構(gòu)造一個(gè)CRuntimeClass 對(duì)象,比擬一個(gè)類是否屬于某個(gè)對(duì)象的時(shí)候,實(shí)際上只是比擬CRuntimeClass對(duì)象.如何在各個(gè)類之中插入 CRuntimeClass對(duì)象,并且指定CRuntimeClass對(duì)象的內(nèi) 容及CRuntimeClass對(duì)象的鏈接,這里起碼有十行的代碼才能完成.在每個(gè)需要 有RTTI水平的類設(shè)計(jì)中都要重復(fù)那十多行代碼是一件乏味的事情,也容易出錯(cuò),所以MFCS了兩個(gè)宏代替這些工作,即 DECLARE_DYNAMC和 IMPLEMENT_DYNAMC,基類名.
37、從這兩個(gè)宏布們可以看出在 MFCg類中的 CRuntimeClass對(duì)象構(gòu)造連接只有類名及基類名的不同!到此,可能會(huì)有朋友問(wèn):為什么要用兩個(gè)宏,用一個(gè)宏不可以代換CRuntimeClass 對(duì)象構(gòu)造連接嗎?個(gè)人認(rèn)為肯定可以, 由于宏只是文字代換的游戲而已. 但我們?cè)诰幊讨?頭文件與源文件是分開的,我們要在頭文件頭聲明變量及方法,在源文件里實(shí)具體實(shí)現(xiàn).即是說(shuō)我們要在頭文件中聲明:public:static CRuntimeClass classXXX /XXX 為類名virtual CRuntime* GetRuntimeClass() const;然后在源文件里實(shí)現(xiàn):CRuntimeClas
38、s* XXX: : classXXX=;CRuntime* GetRuntimeClass() const; return &XXX: classXXX;/ 這里不能直接返回 &classXXX,由于 static 變量 是類擁有而不是對(duì)象擁有.我們一眼可以看出MFOt的DECLARE_DYNAMIC備)宏應(yīng)該這樣定義:#define DECLARE_DYNAMIC(class_name) public: static CRuntimeClassclass#class_name; virtual CRuntimeClass* GetRuntimeClass() const;其中
39、#為連區(qū)符,可以讓我們彳入的類名前面加上class ,否那么跟原類同名,大家會(huì)知道產(chǎn)生什么后果.有了上面的DECLARE_DYNAM佻)宏之后,我們?cè)陬^文件里寫上一句DECLARE_DYNAMIC(XXX)宏展開后就有了我們想要的:public:static CRuntimeClass classXXX /XXX 為類名virtual CRuntime* GetRuntimeClass() const;對(duì)于IMPLEMENT_DYNAM®(,基類名),看來(lái)也不值得在這里代換文字了,大家知道它是知道回手,宏展開后為我們做了什么,再深究真是一點(diǎn)意義都沒(méi)有!有了此鏈表之后,就像有了一張存放
40、各類型的網(wǎng),我們可以輕而易舉地RTTIoCObject 有一個(gè)函數(shù) BOOL IsKindOf(const CRuntimeClass* pClass) const; , 被它以下所有派生員繼承.此函數(shù)實(shí)現(xiàn)如下:BOOL CObject:IsKindOf(const CRuntimeClass* pClass) constCRuntimeClass* pClassThis=GetRuntimeClass();/ 獲得自己的 CRuntimeClass對(duì)象指針.while(pClassThis!=NULL)if(pClassThis=pClass) return TRUE;pClassThis=
41、pClassThis->m_pBaseClass;/這句最關(guān)鍵,指向自己基類,再回頭比擬,一直到盡頭m_pBaseClass為NULL!吉束.return FALSE;MF6大關(guān)鍵技術(shù)(三)動(dòng)態(tài)創(chuàng)立動(dòng)態(tài)創(chuàng)立就是運(yùn)行時(shí)創(chuàng)立指定類的對(duì)象,在MFC大量使用.如框架窗口對(duì)象、視對(duì)象,還有文檔對(duì)象都需要由文檔模板類對(duì)象來(lái)動(dòng)態(tài)的創(chuàng)立.我覺(jué)得這是每個(gè)MFC勺學(xué)習(xí)者很希望理解的問(wèn)題.初次接觸MFC勺時(shí)候,很容易有這樣的迷惘.MFC勺幾大類不用我們?cè)O(shè)計(jì)也就罷 了,但最迷惑的是不用我們實(shí)例化對(duì)象.本來(lái)最直觀的理解就是,我們需要框架 的時(shí)候,親手寫上 CFrameWnd myFrame需要視的時(shí)候,親自打上
42、CView myView;但MFCf給我們這個(gè)時(shí)機(jī),致使我們錯(cuò)覺(jué)窗口沒(méi)有實(shí)例化就彈出來(lái)了!就象畫了張電視機(jī)的電路圖就可以看電視一樣令人難以置信.但大伙想了一下,可能會(huì)一 拍腦門,認(rèn)為簡(jiǎn)單不過(guò):MFC!動(dòng)幫我們完成CView myView之流的代碼不就行 了么! ! !其實(shí)不然,寫MFW序的時(shí)候,我們幾乎要對(duì)每個(gè)大類進(jìn)行派生改寫. 換句話說(shuō),MFC不知道我們打算怎樣去改寫這些類,當(dāng)然也不打算全部為我們“靜態(tài)創(chuàng)立這些類了.即使靜態(tài)了創(chuàng)立這些類也沒(méi)有用,由于我們從來(lái)也不會(huì) 直接利用這些類的實(shí)例干什么事情.我們只知道,想做什么事情就往各大類里塞, 不管什么變量、方法照塞,塞完之后,我們似乎并未實(shí)例化對(duì)
43、象,程序就可以運(yùn) 行!要做到把自己的類交給 MFC MFCM用同一樣的方法,把不同的類一一準(zhǔn)確創(chuàng)立, 我們要做些什么事情呢?同樣地, 我們要建立鏈表,記錄各類的關(guān)鍵信息,在動(dòng) 態(tài)創(chuàng)立的時(shí)候找出這些信息,就象上一節(jié) RTTI那樣!我們可以設(shè)計(jì)一個(gè)類:struct CRuntimeClassLPCSTR m_lpszClassName; 類名指針CObject* (PASCAL *m_pfnCreateObject)(); 創(chuàng)立對(duì)象的函數(shù)的指針CRuntimeClass* m_pBaseClass; / 講 RTTI 時(shí)介紹過(guò)CRuntimeClass* m_pNextClass; /指向鏈表的下
44、一個(gè)元素(許多朋友說(shuō)上一節(jié)講 RTTI時(shí)并沒(méi)有用到五個(gè)指針,我原本以為這樣更好理解一些,由于沒(méi)有這個(gè)指針,這個(gè)鏈表是無(wú)法連起來(lái),而 m_pBaseClass僅僅是向基類走,在 MFC勺樹型 層次結(jié)構(gòu)中m_pBaseClass是不能遍歷的)CObject* CreateObject(); / 創(chuàng)立對(duì)象static CRuntimeClass* PASCAL Load(); /遍歷整個(gè)類型鏈表,返回符合動(dòng)態(tài)創(chuàng)立的對(duì)象.static CRuntimeClass* pFirstClass; /類型鏈表的頭指針;一下子往結(jié)構(gòu)里面塞了那么多的東西,大家可以覺(jué)得有點(diǎn)頭暈.至于 CObject* PASCAl
45、*m_pfnCreateObject;,這定義函數(shù)指針的方法,大家可能有點(diǎn)陌生. 函數(shù)指針在C+瑋籍里一般被定為選學(xué)章節(jié),但 MFC3S是經(jīng)常用到此類的函數(shù), 比方我們所熟悉的回調(diào)函數(shù).簡(jiǎn)單地說(shuō)m_pfnCreateObject即是保存了一個(gè)函數(shù) 的地址,它將會(huì)創(chuàng)立一個(gè)對(duì)象.即是說(shuō),以后, m_pfnCreateObject指向不同的 函數(shù),我們就會(huì)創(chuàng)立不同類型的對(duì)象.有函數(shù)指針,我們要實(shí)現(xiàn)一個(gè)與原定義參數(shù)及返回值都相同一個(gè)函數(shù),在 MFC 中定義為:static CObject* PASCAL CreateObjectreturn new XXX;/XXX 為類名.類 名不同,我們就創(chuàng)立不同
46、的對(duì)象.由此,我們可以如下構(gòu)造 CRuntimeClass到鏈表:CRuntimeClass classXXX=類名,XXX:CreateObject , /m_pfnCreateObject 指向的函數(shù)RUNTIME_CLASSfe名 RUNTIME_CLASS宏可以返回 CRuntimeClass 對(duì)象指 針.NULL /m_pNextClass暫時(shí)為空,最后會(huì)我們?cè)僭O(shè)法讓它指向舊鏈表表頭.;這樣,我們用函數(shù)指針 m_pfnCreateObject 指向CreateObject函數(shù),就隨時(shí) 可new新對(duì)象了.并且大家留意到,我們?cè)谠O(shè)計(jì)CRuntimeClass類對(duì)時(shí)候,只有 類名和基類名的
47、不同我們用 XXX代替的地方,其它的地方一樣,這正是 我們想要的,由于我們動(dòng)態(tài)創(chuàng)立也象 RTTI那樣用到兩個(gè)宏,只要傳入類名和基 類作宏參數(shù),就可以滿足條件.即是說(shuō),我們類說(shuō)明中使用 DECLARE_DYNCREACEASSNMA弦和在類的實(shí)現(xiàn) 文件中使用IMPLEMENT_DYNCREACEASSNAM田ASECLASS宏來(lái)為我們力口入鏈 表,至于這兩個(gè)宏怎么為我7門建立一個(gè)鏈表,我們自己可以玩玩文字代換的游戲, 在此不累贅.但要說(shuō)明的一點(diǎn)就是:動(dòng)態(tài)創(chuàng)立宏xxx_DYNCREATE含了 RTTI宏,即是說(shuō),xxx_DYNCREAT是 xxx_DYNAMlC勺“增強(qiáng)版.到此,我們有必要了解一下
48、上節(jié)課沒(méi)有明講的m_pNextClass指針.由于MFCS次結(jié)構(gòu)是樹狀的,并不是直線的.如果我們只有一個(gè)m_pBaseClass指針,它只會(huì)沿著基類上去,會(huì)漏掉其它分支.在動(dòng)態(tài)創(chuàng)立時(shí),必需如僉查整個(gè)鏈表,看有 多少個(gè)要?jiǎng)討B(tài)創(chuàng)立的對(duì)象,即是說(shuō)要從表頭pFirstClass 開始一直遍歷到表 尾m_pNextClass=NULL ,不能漏掉一個(gè) CRuntimeClass 對(duì)象.所以每當(dāng)有一個(gè)新的鏈表元素要參加鏈表的時(shí)候,我們要做的就是使新的鏈表元素成為表頭,并且m_pNextClass指向原來(lái)鏈表的表頭,即像下面那樣當(dāng)然, 這些不需要我們操心,是 RTTI宏幫助我們完成的:pNewClass-&
49、gt;m_pNextClass=CRuntimeClass:pFirstClass;/新元素的m_pNextClass指針指向想?yún)⒓拥逆湵淼谋眍^.CRuntimeClass:pFirstClass=pNewClass;/鏈表的頭指針指向剛插入的新元素.好了,有了上面的鏈表,我們就可以分析動(dòng)態(tài)創(chuàng)立了.有一了張有類名,函數(shù)指針,動(dòng)態(tài)創(chuàng)立函數(shù)的鏈表,我們就可以知道應(yīng)該按什么 步驟去動(dòng)態(tài)創(chuàng)立了: 1、獲得一要?jiǎng)討B(tài)創(chuàng)立的類的類名假設(shè)為 A.2、將A跟 鏈表里面每個(gè)元素的m_lpszClassName指向的類名作比擬.3、假設(shè)找到跟A相同 的類名就返回A所屬的CRuntimeClass元素的指針.4、判斷
50、m_pfnCreateObject 是否有指向創(chuàng)立函數(shù),有那么創(chuàng)立對(duì)象,并返回該對(duì)象.代碼演示如不以下兩個(gè) 函數(shù)都是CRuntimeClass類函數(shù):/以下為根據(jù)類名從表頭向表尾查找所屬的CRuntimeClass對(duì)象/CRuntimeClass* PASCAL CRuntimeClass:Loadchar szClassXXX64;CRuntimeClass* pClass;cin>>szClassXXX; /假定這是我們希望動(dòng)態(tài)創(chuàng)立的類名 for(pClass=pFirstClass;pClass!=NULL;pClass=pClass->m_pNextClass)(if
51、(strcmp(szClassXXX,pClass->m_lpszClassName)=0)return pClass;return NULL/ 根據(jù) CRuntimeClass 創(chuàng)立對(duì)象 /CObject* CRuntimeClass:CreateObject()(if(m_pfnCreateObject=NULL) return NULL;CObject *pObject;pObject=(* m_pfnCreateObject)(); /函數(shù)指針調(diào)用return pObject;有了上面兩個(gè)函數(shù),我們?cè)诔绦驁?zhí)行的時(shí)候調(diào)用,就可以動(dòng)態(tài)創(chuàng)立對(duì)象了.我們還可以更簡(jiǎn)單地實(shí)現(xiàn)動(dòng)態(tài)創(chuàng)立,大家注
52、意到,就是在我們的程序類里面有一個(gè) RUNTIME_CLASS(class_nam電,這個(gè)宏在 MFC1定義為:RUNTIME_CLASS(class_name)(CRuntimeClass*)(&class_name:class#class_name)作用就是得到類的RunTime信息,即返回class_name所屬CRuntimeClass的對(duì)象.在我們的應(yīng)用程序員類(CMyWinApp)勺InitInstance() 函數(shù)下面的CSingleDocTemplate 函數(shù)中,有:RUNTIME_CLASS(CMyDoc),RUNTIME_CLASS(CMainFrame), / m
53、ain SDI frame windowRUNTIME_CLASS(CMyView)構(gòu)造文檔模板的時(shí)候就用這個(gè)宏得到文檔、框架和視的RunTime信息.有了RunTime信息,我們只要一條語(yǔ)句就可以動(dòng)態(tài)創(chuàng)立了,如:classMyView->CreateObject(); 對(duì)象直接調(diào)用用 CRuntimeClass 本身的CreateObject() 現(xiàn)在,細(xì)心的朋友已經(jīng)能清楚動(dòng)態(tài)創(chuàng)立需要的步驟:1、定義一個(gè)不帶參數(shù)的構(gòu)造函數(shù)(默認(rèn)構(gòu)造函數(shù));由于我們是用CreateObject() 動(dòng)態(tài)創(chuàng)立,它只有一條語(yǔ)句就是return new XXX ,不帶任何參數(shù).所以我們要 有一個(gè)無(wú)參構(gòu)造函數(shù).
54、2、類說(shuō)明中使用 DECLARE_DYNCREACLASSNMAEg;和在類的實(shí)現(xiàn)文件中使 用 IMPLEMENT_DYNCREACEASSNAMEBASECLASS宏;這個(gè)宏完成構(gòu)造 CRuntimeClass對(duì)象,并參加到鏈表中.3、使用時(shí)先通過(guò)宏RUNTIME_CLASS至IJ類的RunTime信息,然后使用 CRuntimeClass的成員函數(shù)CreateObject創(chuàng)立一個(gè)該類的實(shí)例.4、CObject* pObject = pRuntimeClass->CreateObject();/完成動(dòng)態(tài)創(chuàng)立.MF6大關(guān)鍵技術(shù)(四)永久保存(串行化)先用一句話來(lái)說(shuō)明永久保存的重要:弄懂它
55、以后,你就越來(lái)越像個(gè)程序員了!如果我們的程序不需要永久保存,那幾乎可以肯定是一個(gè)小玩兒.那怕我們的記 事本、畫圖等小程序,也需要保存才有真正的意義.對(duì)于MFC勺很多地方我不甚滿意,總覺(jué)得它喜歡拿一組低能而神秘的宏來(lái)故弄玄 虛,但對(duì)于它的連續(xù)存儲(chǔ)(serialize )機(jī)制,卻是我十分鐘愛的地方.在此, 可讓大家感受到面向?qū)ο蟮男腋?MFC勺連續(xù)存儲(chǔ)(serialize )機(jī)制俗稱串行化.“在你的程序中盡管有著各種 各樣的數(shù)據(jù),serialize 機(jī)制會(huì)象流水一樣按順序存儲(chǔ)到單一的文件中,而又能 按順序地取出,變成各種不同的對(duì)象數(shù)據(jù).不知我在說(shuō)上面這一句話的時(shí)候, 大家有什么反響,可能很多朋友直
56、覺(jué)是一件很簡(jiǎn)單的事情,只是說(shuō)了一個(gè)“爽字就沒(méi)有下文了.要實(shí)現(xiàn)象流水一樣存儲(chǔ)其實(shí)是一個(gè)很大的難題.試想,在我們的程序里有各式各 樣的對(duì)象數(shù)據(jù).如畫圖程序中,里面設(shè)計(jì)了點(diǎn)類,矩形類,圓形類等等,它們的 繪圖方式及對(duì)數(shù)據(jù)的處理各不相同,用它們實(shí)現(xiàn)了成百上千的對(duì)象之后,如何存 儲(chǔ)起來(lái)?不想由可,一想頭都大了:我們要在程序中設(shè)計(jì)函數(shù)store(),在我們單擊“文件/保存時(shí)能把各對(duì)象往里存儲(chǔ).那么這個(gè)store()函數(shù)要神通廣闊, 它能清楚地知道我們?cè)O(shè)計(jì)的是什么樣的類,產(chǎn)生什么樣的對(duì)象.大家可能并不覺(jué) 得這是一件很困難的事情,程序有水平知道我們的類的樣子,對(duì)象也不過(guò)是一塊 初始化了存儲(chǔ)區(qū)域罷了.就把一大堆對(duì)象“轉(zhuǎn)換成磁盤文件就行了.即使上面的存儲(chǔ)能成立,但當(dāng)我們單擊“文件
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 冀教版一年級(jí)下冊(cè)數(shù)學(xué)教學(xué)計(jì)劃(含進(jìn)度表)
- 人教版九年級(jí)下冊(cè)數(shù)學(xué)教學(xué)計(jì)劃(及進(jìn)度表)
- 2025年湖北省中考英語(yǔ)模擬試卷(附答案)
- 2025年第十屆安全生產(chǎn)知識(shí)競(jìng)賽經(jīng)典題庫(kù)及答案(共六套)
- 農(nóng)村小吃店開業(yè)致詞簡(jiǎn)短
- 高新科技研發(fā)居間存款合同
- 航空票務(wù)居間服務(wù)合同
- 建筑柴油供應(yīng)居間協(xié)議樣本
- 城市公共交通運(yùn)營(yíng)合同
- 停車場(chǎng)智能門禁管理系統(tǒng)
- 家居家具保養(yǎng)與清潔指導(dǎo)書
- 2023年員工手冊(cè)范本(適用于公司全體員工手冊(cè))
- 2024版北京市家庭居室裝飾裝修工程施工合同
- 不間斷電源UPS知識(shí)培訓(xùn)
- 主題活動(dòng)一 奇妙的繩結(jié)(教學(xué)設(shè)計(jì))內(nèi)蒙古版六年級(jí)上冊(cè)綜合實(shí)踐活動(dòng)
- GB/T 23576-2024拋噴丸設(shè)備通用技術(shù)規(guī)范
- 機(jī)動(dòng)車檢測(cè)站質(zhì)量手冊(cè)(根據(jù)補(bǔ)充技術(shù)要求修訂)
- SH/T 3533-2024 石油化工給水排水管道工程施工及驗(yàn)收規(guī)范(正式版)
- 大隱靜脈射頻消融手術(shù)
- 2023版《思想道德與法治》(緒論-第一章)緒論 擔(dān)當(dāng)復(fù)興大任 成就時(shí)代新人;第一章 領(lǐng)悟人生真諦 把握人生方向 第3講 創(chuàng)造有意義的人生
- 督查工作總結(jié)督查報(bào)告
評(píng)論
0/150
提交評(píng)論