• <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>

            依舊的博客

            技術(shù)學(xué)習(xí)

            C++博客 首頁(yè) 新隨筆 聯(lián)系 聚合 管理
              17 Posts :: 1 Stories :: 2 Comments :: 0 Trackbacks

            #

            關(guān)于Windows程序模型的最重要之處在于,程序是在Windows面向?qū)ο蟮捏w系結(jié)構(gòu)中運(yùn)行的。

            在WinMain()函數(shù)中,程序所進(jìn)行的最重要工作是注冊(cè)窗口類,從而把自定義的窗口過(guò)程提供給Windows。然后程序調(diào)用Windows創(chuàng)建和顯示窗口,由此啟動(dòng)同用戶的交互過(guò)程。在消息循環(huán)中,程序不斷取得消息,但并不進(jìn)行處理,而是將其發(fā)回Windows,由Windows將消息發(fā)給相應(yīng)的窗口過(guò)程。消息循環(huán)的作用在于控制生命期,如果沒(méi)有消息循環(huán),進(jìn)程將立即結(jié)束。

            在較高層次上來(lái)看,一個(gè)可擴(kuò)展的系統(tǒng)會(huì)給模塊提供資源和自由,而模塊應(yīng)當(dāng)配合系統(tǒng)的整體結(jié)構(gòu)。程序執(zhí)行時(shí),Windows會(huì)為其創(chuàng)建進(jìn)程,分配資源,并調(diào)用WinMain()。WinMain()是進(jìn)程入口,也是進(jìn)程出口,在此期間進(jìn)程可以做任何事情,但是為了使用Windows提供的各種便利,它必須符合Windows程序模型,將自己的運(yùn)行結(jié)合到Windows環(huán)境中。作為進(jìn)程出口,WinMain()決定著程序生命期。一個(gè)提供窗口過(guò)程而等待Windows調(diào)用的程序如何維持和結(jié)束自己的生命期呢,應(yīng)該由消息來(lái)決定。當(dāng)進(jìn)程沒(méi)有要處理的消息時(shí),它應(yīng)該等待,所以WinMain()必須知道有沒(méi)有消息,Windows發(fā)給窗口過(guò)程的消息不能繞過(guò)WinMain();當(dāng)進(jìn)程收到特定的消息時(shí),它結(jié)束生命期,所以WinMain()還應(yīng)該了解消息的內(nèi)容。這正是GetMessage()所做的,如果取不到消息就阻塞,如果取到WM_QUIT消息就返回0,結(jié)束消息循環(huán)。那么如果取到普通的消息呢,由WinMain()直接調(diào)用窗口過(guò)程不可以嗎?這種做法有悖于程序由Windows調(diào)用的基本思想,而實(shí)際上也會(huì)出現(xiàn)問(wèn)題。一個(gè)窗口程序可能有很多窗口類,一些窗口類及其窗口過(guò)程是程序自定義的,另一些則是在Windows內(nèi)部定義的,程序看不到其窗口過(guò)程,比如各種控件窗口。窗口程序運(yùn)行起來(lái)以后,這些窗口類互相配合,它們通信的方式就是消息。由于消息指向的窗口過(guò)程可能是自定義的,也可能是Windows內(nèi)部的,只有Windows才能把它們都送到目的地,并保持發(fā)送方式的一致性。所以WinMain()取到消息后,通過(guò)DispatchMessage()將其發(fā)回Windows,由Windows為其調(diào)用適當(dāng)?shù)拇翱谶^(guò)程,直到窗口過(guò)程調(diào)用后返回Windows,DispatchMessage()才返回。(Windows調(diào)用窗口過(guò)程之后控制首先返回Windows,由WinMain()調(diào)用窗口過(guò)程之后控制保持在程序中,這種區(qū)別是否也有作用?不過(guò)經(jīng)我試驗(yàn),在一個(gè)Win32 SDK的Hello程序中改由WinMain()調(diào)用窗口過(guò)程,沒(méi)有發(fā)現(xiàn)什么問(wèn)題)

             
            參考資料:

            1.《Windows程序設(shè)計(jì)》/Charles Petzold 著 北京博彥科技發(fā)展有限公司 譯 北大出版社
            posted @ 2007-04-15 13:08 依舊的博客 閱讀(344) | 評(píng)論 (0)編輯 收藏

            如果在VC中創(chuàng)建一個(gè)控制臺(tái)的EXE和一個(gè)Win32的DLL,從DLL中導(dǎo)出一個(gè)函數(shù),該函數(shù)用new分配一塊內(nèi)存,返回其指針,然后在EXE中調(diào)用該函數(shù),獲得返回的指針,用delete釋放這塊內(nèi)存,就會(huì)引發(fā)斷言錯(cuò)誤。

            產(chǎn)生這個(gè)問(wèn)題的原因是:EXE和DLL中分別靜態(tài)鏈接了C運(yùn)行時(shí)庫(kù),從而new和delete運(yùn)算符來(lái)自C運(yùn)行時(shí)庫(kù)的不同版本。C運(yùn)行時(shí)庫(kù)在管理堆內(nèi)存時(shí),會(huì)使用一些全局變量來(lái)跟蹤內(nèi)存分配情況,因此程序中鏈接的C運(yùn)行時(shí)庫(kù)必須唯一,否則就會(huì)引起不一致。

            解決的辦法很簡(jiǎn)單:在EXE和DLL中都動(dòng)態(tài)鏈接C運(yùn)行時(shí)庫(kù),也就是在工程設(shè)置的Link面板選擇"忽略所有默認(rèn)的庫(kù)",再加入msvcrt.lib。

            對(duì)這個(gè)問(wèn)題有兩種錯(cuò)誤的觀點(diǎn)需要澄清:一種以為EXE和DLL有不同的堆,實(shí)際上DLL總是被映射到加載它的進(jìn)程的地址空間,它沒(méi)有自己的堆;一種以為DLL和EXE相對(duì)于不同的起始地址,動(dòng)態(tài)鏈接的地址映射機(jī)制引起了前面的問(wèn)題,實(shí)際上DLL是和OBJ一樣的目標(biāo)模塊,每個(gè)目標(biāo)模塊都有自己的起始地址,但是鏈接成加載模塊以后就會(huì)統(tǒng)一到一個(gè)起始地址,一個(gè)目標(biāo)模塊對(duì)其它模塊的引用在鏈接前是以符號(hào)方式表示的,鏈接后會(huì)被修改成地址方式。靜態(tài)鏈接和動(dòng)態(tài)鏈接都會(huì)保證:加載模塊是統(tǒng)一編址的。

            參考資料:
            1. http://topic.csdn.net/t/20020714/19/873683.html
            2. MSDN July 2000/Knowledge Base/Windows Development/Win32 Software Development Kit/HOWTO: Use the C Run-Time
            3. 《操作系統(tǒng)-內(nèi)核與設(shè)計(jì)原理(第四版)》/William Stallings 著,魏迎梅等譯 電子工業(yè)出版社

            posted @ 2007-01-28 14:02 依舊的博客 閱讀(311) | 評(píng)論 (0)編輯 收藏

            有兩個(gè)比較基本的問(wèn)題:

            1. 為什么要用異常代替錯(cuò)誤碼?

            錯(cuò)誤碼的缺點(diǎn):

            1) 默認(rèn)是可以忽略的,因?yàn)檎{(diào)用函數(shù)時(shí)可以不處理其返回值,從而錯(cuò)誤處理要依賴于程序員的主動(dòng)性,而不是程序機(jī)制的要求;

            2) 不能跨作用域傳送,必須逐層向上轉(zhuǎn)發(fā),即使中間沒(méi)有對(duì)錯(cuò)誤碼進(jìn)行重新定義;
            ?

            使用異常可以解決解決這兩個(gè)問(wèn)題:

            1) 異常默認(rèn)是不可忽略的,拋出的異常必須捕獲,否則就會(huì)報(bào)錯(cuò);

            2) 異常可以跨作用域傳送,從而錯(cuò)誤的發(fā)現(xiàn)和處理被很好地分離開來(lái);
            ?

            ?

            2. 異常和斷言的區(qū)別:
            ?

            異常被捕獲后可以不作處理,程序從捕獲位置繼續(xù)執(zhí)行。而斷言是完全無(wú)法忽略的,程序在斷言失敗處立即終止。因此斷言通常用于調(diào)試版本,用來(lái)發(fā)現(xiàn)程序中的邏輯錯(cuò)誤。雖然異常也能起到這樣的作用,但是不應(yīng)該用異常代替斷言:
            1) 如果發(fā)現(xiàn)了邏輯錯(cuò)誤,必須修改程序,而不可能在程序中進(jìn)行處理和恢復(fù),所以不需要向外傳送,沒(méi)有必要使用異常。
            2) 使用斷言的開銷比異常小得多,而且斷言可以從發(fā)布版中完全去除。
            ?

            異常用于處理正確程序中的運(yùn)行期問(wèn)題(比如內(nèi)存分配失敗,窗口創(chuàng)建失敗,線程創(chuàng)建失敗,打開文件失敗),以盡可能恢復(fù),而不是終止程序。對(duì)于運(yùn)行異常,使用斷言是非常不合適的,理由很顯然:
            1) 斷言在發(fā)布版不起作用;
            2) 斷言的處理方式不夠友好;
            3) 運(yùn)行異常不是程序錯(cuò)誤,沒(méi)有必要報(bào)告源代碼出錯(cuò)位置;



            參考資料:

            1.《C++編程規(guī)范-101條規(guī)則、準(zhǔn)則與最佳實(shí)踐》/Herb Sutter,Andrei Alexandrescu 著 劉基誠(chéng) 譯 人民郵電出版社
            2.《C++程序設(shè)計(jì)語(yǔ)言》/Bjarne Stroustrup 著?裘宗燕 譯 機(jī)械工業(yè)出版社
            3.《C與C++中的異常處理》/Robert Schmidt 著 無(wú)情 譯 http://download.pchome.net/development/reference/11135.html

            posted @ 2006-10-19 21:28 依舊的博客 閱讀(1445) | 評(píng)論 (0)編輯 收藏

            軟件設(shè)計(jì)中會(huì)碰到這樣的關(guān)系:一個(gè)對(duì)象依賴于另一個(gè)對(duì)象,必須根據(jù)后者的狀態(tài)更新自己的狀態(tài),可以把后者稱作目標(biāo)對(duì)象,前者稱作觀察者對(duì)象。不但觀察者依賴于目標(biāo),當(dāng)目標(biāo)的狀態(tài)改變時(shí)也要通知觀察者,這就出現(xiàn)了雙向的依賴。兩個(gè)對(duì)象互相依賴的后果是它們必須一起復(fù)用。如果一個(gè)目標(biāo)有多個(gè)觀察者,那么目標(biāo)也依賴所有觀察者,從而目標(biāo)對(duì)象無(wú)法獨(dú)立復(fù)用。如何消除目標(biāo)和觀察者之間的互相依賴呢?觀察者模式幫助我們解決這個(gè)問(wèn)題。

            觀察者模式把目標(biāo)對(duì)觀察者的依賴進(jìn)行抽象:使目標(biāo)只知道自己有若干觀察者,但不知道這些觀察者具體是誰(shuí),可能有多少個(gè);當(dāng)目標(biāo)狀態(tài)改變時(shí)只要給這些觀察者一個(gè)通知,不必作更多的事情。這樣目標(biāo)對(duì)觀察者的依賴就達(dá)到了抽象和最小,而目標(biāo)對(duì)具體觀察者的依賴被解除了。

            類圖如下:

            Observer.JPG

            Subject對(duì)象保存一個(gè)Observer引用的列表,當(dāng)我們讓一個(gè)ConcreteObserver對(duì)象觀察Subject對(duì)象時(shí),調(diào)用后者的Attach()方法,將前者的引用加入該列表中。當(dāng)Subject對(duì)象狀態(tài)改變時(shí),它調(diào)用自身的Notify方法,該方法調(diào)用列表中每一個(gè)Observer的Update()方法。一個(gè)ConcreteObserver只要重定義Update()就能收到通知,作為對(duì)通知的響應(yīng),Update()調(diào)用Subject對(duì)象的getStatus()獲取數(shù)據(jù),然后更新自身。當(dāng)不需要繼續(xù)觀察時(shí),ConcreteObserver對(duì)象調(diào)用Subject對(duì)象的Detach()方法,其引用被從列表中移除。

            解除目標(biāo)對(duì)具體觀察者的依賴以后,很容易增加新的具體觀察者,因?yàn)椴皇芤蕾嚨姆矫婢涂梢宰杂勺兓欢繕?biāo)也可以獨(dú)立地復(fù)用,因?yàn)闊o(wú)所依賴的方面就可以不受影響。

            以上主要考慮了一個(gè)目標(biāo)有多個(gè)觀察者的情況,我們?cè)O(shè)法解除了目標(biāo)對(duì)具體觀察者的依賴,使具體觀察者的種類和數(shù)目容易改變。有時(shí)候一個(gè)觀察者觀察多個(gè)目標(biāo)也是有意義的,在前面的類圖中,觀察者對(duì)具體目標(biāo)的依賴仍然存在,因此無(wú)法適應(yīng)目標(biāo)方面的變化。怎樣抽象這種依賴呢?使觀察者只知道若干個(gè)目標(biāo)會(huì)向自己發(fā)出通知,而不知道這些目標(biāo)具體是誰(shuí),可能有多少個(gè);在目標(biāo)向觀察者發(fā)送通知時(shí),將一個(gè)自身的引用作為參數(shù),然后觀察者調(diào)用其抽象方法就可以獲得目標(biāo)狀態(tài)。這就使得觀察者對(duì)目標(biāo)的依賴是抽象的,觀察者對(duì)具體目標(biāo)的依賴被解除了。

            類圖如下:

            Observer2.JPG

            參考資料:

            1.《設(shè)計(jì)模式-可復(fù)用面向?qū)ο筌浖幕A(chǔ)》/Erich Gamma等著,李英軍等譯 機(jī)械工業(yè)出版社

            posted @ 2006-09-10 12:53 依舊的博客 閱讀(2287) | 評(píng)論 (0)編輯 收藏

            Factory Method-創(chuàng)建多種同類產(chǎn)品的工廠:

            為一類產(chǎn)品 ( 一個(gè)抽象產(chǎn)品及其所有具體產(chǎn)品 ) 提供一個(gè)工廠,該類的每一種具體產(chǎn)品由工廠中的一個(gè)方法創(chuàng)建。種種做法的缺點(diǎn)是不易增加新的具體產(chǎn)品,每增加一個(gè)具體產(chǎn)品,工廠中就要增加一個(gè)方法,這意味著工廠的所有使用者都要重新編譯。可以用參數(shù)化的方法來(lái)改進(jìn),工廠只提供一個(gè)接受參數(shù)的創(chuàng)建函數(shù),參數(shù)的取值標(biāo)志了某種具體產(chǎn)品,在創(chuàng)建函數(shù)中對(duì)參數(shù)進(jìn)行判斷,根據(jù)不同的參數(shù)值創(chuàng)建不同的具體產(chǎn)品并返回。這就減小了增加具體產(chǎn)品的代價(jià),每增加一種具體產(chǎn)品時(shí)只要修改工廠的創(chuàng)建函數(shù)的實(shí)現(xiàn)即可。

            原來(lái)是用工廠的不同方法創(chuàng)建不同的具體對(duì)象,現(xiàn)在是用同一個(gè)方法的不同參數(shù)創(chuàng)建不同的具體對(duì)象。還可以用抽象工廠的不同派生類來(lái)創(chuàng)建不同的具體對(duì)象,這種做法比較笨重.

            Abstract Factory-可替換的工廠:

            見(jiàn)參考資料1


            參考資料:

            1.《設(shè)計(jì)模式-可復(fù)用面向?qū)ο筌浖幕A(chǔ)》/Erich Gamma等著,李英軍等譯 機(jī)械工業(yè)出版社
            2.《敏捷軟件開發(fā)-原則,模式與實(shí)踐》/Robert C.Martin著 鄧輝譯??清華大學(xué)出版社

            posted @ 2006-08-08 13:01 依舊的博客 閱讀(300) | 評(píng)論 (0)編輯 收藏

            MVC(Model-View-Controller)模式的基本思想是數(shù)據(jù),顯示和處理相分離。模型(Model)負(fù)責(zé)數(shù)據(jù)管理,視圖(View)負(fù)責(zé)數(shù)據(jù)顯示,控制器(Controller)負(fù)責(zé)業(yè)務(wù)邏輯和響應(yīng)策略。

            從MVC的形成過(guò)程來(lái)看,最初只有模型和視圖兩個(gè)元素。模型封裝了數(shù)據(jù)并提供操作接口,視圖用來(lái)表現(xiàn)數(shù)據(jù)和接收用戶請(qǐng)求。模型是獨(dú)立的,而視圖依賴于模型:從模型獲取數(shù)據(jù)進(jìn)行顯示;向模型發(fā)送用戶請(qǐng)求,并根據(jù)返回結(jié)果刷新自己。

            需要用多個(gè)視圖表現(xiàn)同一模型時(shí),情況發(fā)生了變化:一個(gè)視圖修改數(shù)據(jù)以后,不但本身要刷新,其他所有視圖也要刷新。如果由該視圖通知其他視圖,它就需要知道其他所有視圖,由于每個(gè)視圖都可能發(fā)出修改,每個(gè)視圖都要知道其他所有視圖,這種關(guān)聯(lián)過(guò)于復(fù)雜,不但難以維護(hù),而且不便于增加新的視圖。如果讓模型通知所有視圖更新,可能會(huì)影響模型的獨(dú)立性。用觀察者(Observer)模式可以解決上述矛盾,從而實(shí)現(xiàn):由模型通知視圖,而模型不依賴于具體的視圖,具體視圖之間相互獨(dú)立。

            視圖是用戶請(qǐng)求的接收者,但不宜作為請(qǐng)求的處理者。因?yàn)榻缑媸且鬃兊模绻麡I(yè)務(wù)代碼和界面代碼放在一起,頻繁的界面修改可能會(huì)破壞比較穩(wěn)定的業(yè)務(wù)代碼。將業(yè)務(wù)邏輯分離出來(lái),由一個(gè)控制器負(fù)責(zé),就是為了避免這種干擾。

            模型,視圖和控制器的基本協(xié)作關(guān)系如下圖

            MVC模式協(xié)作圖.gif

            模型在狀態(tài)變化的時(shí)候,直接通知所有視圖,視圖向模型查詢狀態(tài)數(shù)據(jù),然后刷新自身。當(dāng)用戶發(fā)出操作時(shí),視圖把消息發(fā)給控制器,控制器按照業(yè)務(wù)邏輯進(jìn)行處理,需要查詢或更新數(shù)據(jù)時(shí),控制器會(huì)調(diào)用模型。下面是一個(gè)更詳細(xì)的示意圖

            MVC模式協(xié)作圖2.gif


            同樣的數(shù)據(jù),可以有不同的顯示和進(jìn)行各種處理。顯示僅僅是表現(xiàn)數(shù)據(jù),而處理是根據(jù)用戶請(qǐng)求改變數(shù)據(jù)的過(guò)程,不但包含業(yè)務(wù)邏輯,也要提供響應(yīng)策略。響應(yīng)策略由控制器負(fù)責(zé),視圖可以使用不同的控制器提供不同的響應(yīng)方式,這是策略(Strategy)模式的應(yīng)用。

            此外,MVC還允許視圖嵌套,通過(guò)使用組合(Composite)模式,一致地處理組合視圖和普通視圖。

            用多個(gè)視圖表現(xiàn)一個(gè)模型,在視圖不變的情況下改變響應(yīng)策略,允許視圖嵌套,這是MVC的三個(gè)主要特性。在內(nèi)部結(jié)構(gòu)上,MVC的主要關(guān)系是由觀察者模式,策略模式和組合模式給出的。由觀察者模式確定的模型視圖關(guān)系是其中最為重要的。

            MVC模式有許多變體。前述結(jié)構(gòu)中,由模型通知視圖刷新,稱為主動(dòng)MVC;如果由控制器更新模型以后通知視圖,稱為被動(dòng)MVC結(jié)構(gòu)。在許多應(yīng)用中,沒(méi)有明顯的控制器角色,也沒(méi)有視圖嵌套。可見(jiàn)根據(jù)實(shí)際需要,構(gòu)成MVC的三個(gè)模式上都可能出現(xiàn)變化。Web瀏覽器就是被動(dòng)MVC結(jié)構(gòu)的一個(gè)實(shí)例。
            “瀏覽器是一個(gè)交互程序,從概念上講,它是由一組客戶、一組解釋器與一個(gè)管理它們的控制器所組成。控制器形成了瀏覽器的中心部件,它解釋鼠標(biāo)點(diǎn)擊與鍵盤輸入,并且調(diào)用其他組件來(lái)執(zhí)行用戶指定的操作。例如,當(dāng)用戶鍵入一個(gè)URL或者點(diǎn)擊一個(gè)超文本引用時(shí),控制器調(diào)用一個(gè)客戶從所需文檔所在的遠(yuǎn)程服務(wù)器上取回該文檔,并且調(diào)用解釋器向用戶顯示該文檔。每個(gè)瀏覽器必須包含一個(gè)HTML解釋器來(lái)顯示文檔,其他解釋器是可選的。HTML解釋器的輸入由符合HTML語(yǔ)法的文檔所組成,輸出由位于用戶顯示器上的格式版本文檔所組成。解釋器通過(guò)將HTML規(guī)則轉(zhuǎn)換成適合用戶顯示硬件的命令來(lái)處理版面細(xì)節(jié)。HTML解釋器一個(gè)最重要的功能是包含可選項(xiàng)。解釋器必須存儲(chǔ)關(guān)于顯示器上位置之間關(guān)系的信息和HTML文檔中被瞄定的項(xiàng)。當(dāng)用戶用鼠標(biāo)選定了一個(gè)項(xiàng),瀏覽器通過(guò)當(dāng)前的光標(biāo)位置和存儲(chǔ)的位置信息來(lái)決定哪個(gè)項(xiàng)被用戶選定。”(參考資料5)


            MFC的文檔/視圖結(jié)構(gòu)(Document/View architecture)是MVC模式的一種變體,下面討論它是怎樣實(shí)現(xiàn)的。

            文檔/視圖結(jié)構(gòu)沒(méi)有體現(xiàn)業(yè)務(wù)邏輯和視圖的分離,但是將響應(yīng)策略和視圖區(qū)分開來(lái)。它主要包含四種對(duì)象:

            1. 文檔
            2. 視圖
            3. 視圖框架窗口
            4. 文檔模板

            這里的視圖框架窗口定義了視圖對(duì)用戶輸入的響應(yīng)方式,而文檔模板用來(lái)管理前三種對(duì)象的組合。文檔,視圖,視圖框架窗口三者是對(duì)應(yīng)的,從而構(gòu)成一個(gè)三元組。一個(gè)應(yīng)用程序可能需要多個(gè)這樣的三元組,以實(shí)現(xiàn)文檔的多視圖,所以引入文檔模板來(lái)表示該三元組。因?yàn)槌绦蛑锌赡苁褂枚鄠€(gè)文檔模板,MFC用一個(gè)文檔管理者對(duì)象來(lái)管理它們。

            在MFC中,應(yīng)用程序和主框架窗口是用來(lái)封裝底層機(jī)制的對(duì)象,文檔,視圖,視圖框架窗口和文檔模板是用來(lái)構(gòu)架文檔/視圖結(jié)構(gòu)的對(duì)象。應(yīng)用程序通過(guò)文檔管理者來(lái)使用文檔/視圖結(jié)構(gòu)。

            如果要給文檔增加一種視圖,只需要增加一個(gè)文檔模板;如果要改變一種視圖的響應(yīng)策略,只要改變對(duì)應(yīng)文檔模板中的視圖框架窗口。

            <未完待續(xù)>


            參考資料:

            1.《設(shè)計(jì)模式-可復(fù)用面向?qū)ο筌浖幕A(chǔ)》/Erich Gamma等著,李英軍等譯 機(jī)械工業(yè)出版社
            2.《Java與模式》/閻宏 電子工業(yè)出版社
            3.  模型-視圖-控制器 ( MSDN > 技術(shù)資源庫(kù) > 體系結(jié)構(gòu) > 使用 Microsoft .NET 的企業(yè)解決方案模式 >第3章 Web 表示模式)
            4. 《Java設(shè)計(jì):對(duì)象,UML和過(guò)程》/Kirk Knoernschild 著,羅英偉等譯 人民郵電出版社
            5. 《計(jì)算機(jī)網(wǎng)絡(luò)與因特網(wǎng)》/D.E.Comer 著 徐良賢等譯 機(jī)械工業(yè)出版社
            6.《深入解析MFC》/中國(guó)電力出版社
            7.《VC技術(shù)內(nèi)幕》第5版 / 希望電子出版社

            posted @ 2006-08-06 10:05 依舊的博客 閱讀(3048) | 評(píng)論 (0)編輯 收藏

            1. 一個(gè)用例可以有多個(gè)參與者,并且可以同時(shí)有多個(gè)參與者。
            用例和參與者的關(guān)聯(lián)可以是雙向的,參與者和用例都可以發(fā)起通信。

            2. 用例之間的基本關(guān)系有:泛化,包含和擴(kuò)展。
            用例A到B的泛化關(guān)系表示A和B是具體與抽象的關(guān)系。
            用例A到B的包含關(guān)系表示A使用了B提供的功能。
            用例A到B的擴(kuò)展關(guān)系表示A向B提供的可用的功能。
            但從A到B的包含關(guān)系和從B到A的擴(kuò)展關(guān)系是不同的:
            A包含B說(shuō)明B是從A中分解出來(lái)的公共行為;B自身是獨(dú)立的,但對(duì)于A來(lái)說(shuō)是不可缺少的一部分。
            B擴(kuò)展A說(shuō)明B是從A中分解出來(lái)的變體行為,必須指定擴(kuò)展點(diǎn),也就是在基本用例中執(zhí)行變體行為的具體條件。B僅僅是A的補(bǔ)充,而不是不可缺少的部分,B自身也不是獨(dú)立的。A可以單獨(dú)執(zhí)行,表示通常的情況,在特定的情況下,用B來(lái)補(bǔ)充它。
            抽象用例不能被實(shí)例化,不能被實(shí)際執(zhí)行,它的作用在于更好地組織用例關(guān)系。




            參考書:
            《UML用戶指南》/Grady Booch,James Rumbaugh,Ivar Jacobson著 邵維忠等譯 機(jī)械工業(yè)出版社
            《統(tǒng)一軟件開發(fā)過(guò)程》/Ivar Jacobson,Grady Booch,James Rumbaugh著 周伯生等譯 機(jī)械工業(yè)出版社

            posted @ 2006-06-01 17:18 依舊的博客 閱讀(471) | 評(píng)論 (0)編輯 收藏

            我曾經(jīng)在有一個(gè)Windows XP的機(jī)器上另裝一個(gè)Windows 2000,結(jié)果2000裝完后XP不能啟動(dòng)了。后來(lái)上網(wǎng)看了一些資料,又幾經(jīng)試驗(yàn),解決了這個(gè)問(wèn)題。這里總結(jié)一下其中的原理,這個(gè)現(xiàn)象很容易在重裝低版本系統(tǒng)后出現(xiàn),而且弄清原理以后,我們可以更自由地處理多系統(tǒng)安裝的問(wèn)題。

            單個(gè)操作系統(tǒng)的引導(dǎo)過(guò)程是這樣的:首先,主引導(dǎo)記錄(MBR)被加載到內(nèi)存運(yùn)行,它讀取磁盤分區(qū)表(DPT),查找第一個(gè)活動(dòng)分區(qū)(可引導(dǎo)分區(qū)),該分區(qū)的引導(dǎo)扇區(qū)存放著操作系統(tǒng)的引導(dǎo)記錄。然后,系統(tǒng)引導(dǎo)記錄被加載到內(nèi)存運(yùn)行,它從系統(tǒng)安裝目錄讀取系統(tǒng)的啟動(dòng)文件,將其加載執(zhí)行,控制隨后的啟動(dòng)過(guò)程。

            這里面涉及到一些程序和數(shù)據(jù),它們存放在不同的地方,在不同階段運(yùn)行。第一段程序MBR,它的數(shù)據(jù)是DPT,它們存放在磁盤的主引導(dǎo)扇區(qū)。第二段程序是系統(tǒng)引導(dǎo)記錄,存放在系統(tǒng)所在分區(qū)的引導(dǎo)扇區(qū)。第三段程序是系統(tǒng)啟動(dòng)文件,存放在系統(tǒng)所在分區(qū)系統(tǒng)安裝目錄中。這三段程序像接力跑一樣,前一段程序的工作就是加載后一段程序,并把控制交給它。 引導(dǎo)記錄和啟動(dòng)文件隨操作系統(tǒng)而不同, 是在安裝時(shí)形成的,每個(gè)系統(tǒng)的安裝程序都把其引導(dǎo)記錄寫入安裝分區(qū)的引導(dǎo)扇區(qū),而啟動(dòng)文件是系統(tǒng)的一部分。

            上面的引導(dǎo)過(guò)程有一個(gè)基本缺陷,就是只能引導(dǎo)一個(gè)系統(tǒng),并且只能引導(dǎo)裝在第一活動(dòng)分區(qū)的系統(tǒng)。

            如果一個(gè)操作系統(tǒng)不在活動(dòng)分區(qū),那么該系統(tǒng)要被引導(dǎo)有三種辦法,改寫MBR,改寫第一活動(dòng)分區(qū)引導(dǎo)記錄,或把所在分區(qū)設(shè)為第一活動(dòng)分區(qū)。最后一種做法是不方便的,系統(tǒng)通常會(huì)改寫前兩段引導(dǎo)程序,那么它在解決自身引導(dǎo)問(wèn)題的同時(shí),也不能破壞其他系統(tǒng)的引導(dǎo),這就引出了多系統(tǒng)地引導(dǎo)問(wèn)題。常見(jiàn)的做法是系統(tǒng)提供一個(gè)啟動(dòng)管理器接管引導(dǎo)過(guò)程。啟動(dòng)管理器能夠獲得機(jī)器上多個(gè)系統(tǒng)的引導(dǎo)記錄,從而可以根據(jù)用戶選擇啟動(dòng)不同的系統(tǒng)。系統(tǒng)在安裝時(shí)改寫磁盤第一活動(dòng)分區(qū)的引導(dǎo)記錄,使啟動(dòng)管理器被作為第三段程序加載。

            如果啟動(dòng)管理器能夠知道機(jī)器上每個(gè)系統(tǒng)所在的分區(qū),就能獲得該系統(tǒng)的引導(dǎo)記錄,從而可以引導(dǎo)該系統(tǒng)。但實(shí)際上,啟動(dòng)管理器所屬系統(tǒng)的引導(dǎo)記錄是不能再次被加載的,必須特殊對(duì)待。同一系列的系統(tǒng),也可能有類似的問(wèn)題。所以啟動(dòng)管理器可能要了解機(jī)器上每個(gè)系統(tǒng)具體如何啟動(dòng),相應(yīng)進(jìn)行引導(dǎo)。這樣只有讓高版本的系統(tǒng)提供啟動(dòng)管理器,因?yàn)榈桶姹镜膯?dòng)管理器無(wú)法啟動(dòng)高版本系統(tǒng)。
            2000/XP的啟動(dòng)管理器是OS Loader。它對(duì)98和2000/XP的引導(dǎo)就是不同的,對(duì)98是加載98引導(dǎo)記錄的鏡像文件,對(duì)2000/XP是加載HAL.DLL等文件。OS Loader在引導(dǎo)多系統(tǒng)時(shí),對(duì)于windows系列的引導(dǎo)有特殊性,必須向下兼容。

            OS Loader的載體是ntldr文件,它運(yùn)行時(shí)還會(huì)讀取一個(gè)配置文件boot.ini,兩個(gè)文件都存放在磁盤第一活動(dòng)分區(qū)根目錄。boot.ini記錄了每個(gè)系統(tǒng)所在的分區(qū),每個(gè)版本的windows在安裝時(shí)都會(huì)在boot.ini中填寫有關(guān)自身的一項(xiàng)。2000/XP在安裝時(shí)都會(huì)更新OS Loader和重寫第一活動(dòng)分區(qū)的引導(dǎo)記錄,后安裝者的兩個(gè)程序才會(huì)被保留。如果后裝2000,由于前述的OS Loader版本問(wèn)題,就可能無(wú)法引導(dǎo)XP。

            posted @ 2006-05-18 16:27 依舊的博客 閱讀(921) | 評(píng)論 (0)編輯 收藏

            我們知道MFC的作用在于封裝Windows的編程接口,并提供應(yīng)用程序框架的開發(fā)模式。為了完成從前者到后者的過(guò)渡,MFC實(shí)現(xiàn)了幾種基本機(jī)制,它們是消息映射,命令傳遞,運(yùn)行時(shí)類信息(RTCI),動(dòng)態(tài)創(chuàng)建和序列化。

            消息映射和命令傳遞是對(duì)SDK程序交互機(jī)制的封裝。序列化是應(yīng)用程序需要的一種基本特性,即把數(shù)據(jù)保存到磁盤和從磁盤打開數(shù)據(jù)。通過(guò)RTCI和動(dòng)態(tài)創(chuàng)建,可以把軟件的對(duì)象數(shù)據(jù)保存到磁盤,反過(guò)來(lái)從這些數(shù)據(jù)識(shí)別和恢復(fù)對(duì)象,從而實(shí)現(xiàn)對(duì)象的序列化。基于數(shù)據(jù)庫(kù)的序列化機(jī)制和這種方式不同,應(yīng)用程序和數(shù)據(jù)庫(kù)之間有一個(gè)約定,以什么樣的格式保存什么樣的數(shù)據(jù),再以同樣的方式打開,并且如何重建對(duì)象數(shù)據(jù)也定下來(lái)了,在打開數(shù)據(jù)時(shí),應(yīng)用程序不需要有適應(yīng)性,不需要識(shí)別數(shù)據(jù)類型,也不需要根據(jù)在運(yùn)行期才確定的類型名稱創(chuàng)建其對(duì)象。

            動(dòng)態(tài)創(chuàng)建就是創(chuàng)建某種類型的對(duì)象,具體類型在運(yùn)行時(shí)確定,編譯時(shí)可能不知道。比如運(yùn)行時(shí)用戶輸入一個(gè)類型名稱,如果該類型是程序類型體系中的一員,則程序中將能夠創(chuàng)建該類型的對(duì)象。下面的代碼是使用MFC動(dòng)態(tài)創(chuàng)建機(jī)制的一個(gè)簡(jiǎn)化的例子:

            CRuntimeClass* g_pFirstClass;
            void func()
            {
                 char szClassName[64];
                 CRuntimeClass* pClass;
                 CObject* pObject;
                
                 cout << "enter a class name...  ";
                 cin >> szClassName;
                
                 for (pClass = g_pFirstClass; pClass != NULL; pClass = pClass->m_pNextClass)
                 {
                      if (strcmp(szClassName, pClass->m_lpszClassName) == 0)
                          pObject = pClass->CreateObject();
                 }
            }

            實(shí)現(xiàn)動(dòng)態(tài)創(chuàng)建的思路是把動(dòng)態(tài)的類型名稱與程序類型體系中的每一個(gè)進(jìn)行比較,與某個(gè)類型吻合時(shí)讓該類型創(chuàng)建自身的對(duì)象。這樣,支持動(dòng)態(tài)創(chuàng)建的類庫(kù)中的每一個(gè)類都要額外實(shí)現(xiàn)一些功能,即判別一個(gè)名稱是否與自身相符,以及創(chuàng)建自身的對(duì)象。

            判別一個(gè)名稱是否與自身相符,這是運(yùn)行時(shí)類識(shí)別的內(nèi)容,所以MFC動(dòng)態(tài)創(chuàng)建是在RTCI基礎(chǔ)上實(shí)現(xiàn)的。

            RTCI是一個(gè)對(duì)象能夠判定自己是否屬于某種類型,該類型的名稱在運(yùn)行時(shí)確定,編譯時(shí)可能不知道。從下面的例子很容易理解RTCI,

            void Func()
            {
                 char szClassName[64];
                 CDocument* pDoc = new CDocument;
                
                 cout << "enter a class name...  ";
                 cin >> szClassName;
                
                 cout << pDoc->IsKindOf(szClassName); //是返回1,否返回0
            }

            有一點(diǎn)需要說(shuō)明的是,因?yàn)镃Document派生于CObject,所以IsKindOf對(duì)于CObject也要返回1。因?yàn)槲覀兪菑膭?dòng)態(tài)創(chuàng)建出發(fā)的,所以如果是這樣可能會(huì)有一點(diǎn)背離初衷。但是RTCI明顯和動(dòng)態(tài)創(chuàng)建有密切聯(lián)系,RTCI也可能有單獨(dú)的價(jià)值,所以先把RTCI實(shí)現(xiàn)起來(lái)。

            實(shí)現(xiàn)RTCI的思路是讓每一個(gè)類記錄自身的類型信息,并提供IsKindOf(char*)函數(shù)進(jìn)行所給類型與自身類型的比較,而且還要能訪問(wèn)基類的類型信息,進(jìn)行比較,一直到根類。所以記錄的類型信息要按繼承關(guān)系連起來(lái),每個(gè)類的IsKindOf()還要調(diào)用基類的IsKindOf()。MFC把要記錄的類型信息抽取到一個(gè)CRuntimeClass結(jié)構(gòu)體中,每個(gè)類中加入一個(gè)CRuntimeClass成員即可。

            現(xiàn)在回到動(dòng)態(tài)創(chuàng)建,在RTCI建立的數(shù)據(jù)結(jié)構(gòu)基礎(chǔ)上將可實(shí)現(xiàn)它。動(dòng)態(tài)創(chuàng)建從不同于IsKindOf()的角度使用這一數(shù)據(jù)結(jié)構(gòu),它要遍歷所有類型的CRuntimeClass。那么僅僅有繼承關(guān)系的類的CRuntimeClass相連還不夠,要把所有類的CRuntimeClass連成一個(gè)鏈表。其實(shí)動(dòng)態(tài)創(chuàng)建并不關(guān)心類間的繼承關(guān)系,它平等看待每個(gè)類。現(xiàn)在以CRuntimeClass為結(jié)點(diǎn)構(gòu)成一個(gè)縱橫兩個(gè)方向的鏈表,IsKindOf()和動(dòng)態(tài)創(chuàng)建分別使用它不同的側(cè)面。

            序列化的概念是在文件中存儲(chǔ)對(duì)象信息,并能根據(jù)它恢復(fù)對(duì)象。對(duì)于文檔視圖結(jié)構(gòu)的軟件,用戶需要保存所編輯的文檔和打開已編輯的文檔,這正是序列化的應(yīng)用,所以序列化是非常重要的一種特性。在序列化恢復(fù)對(duì)象時(shí),就可以用到動(dòng)態(tài)創(chuàng)建。

            使用MFC序列化的例子如下,

            void CMyDocument::Serialize(CArichive &ar)
            {
                if (ar.IsStoring())
                {
                    ar << m_pMyClass; //CMyClass m_pMyClass;
                }
                else
                {
                    ar >> m_pMyClass;
                }
            }

            一個(gè)支持序列化的類提供Serialize(CArchive &)函數(shù),重載<<和>>操作。注意兩者是不同的,在上例中,CMyDocument類的信息并不被序列化,而CMyClass類的信息被序列化。實(shí)際上一個(gè)序列化類的<<和>>操作,其不涉及類信息的部分是調(diào)用Serialize()完成的,它必須同時(shí)實(shí)現(xiàn)這兩者。

            按照MFC的要求,需要在支持序列化的類定義中使用DECLARE_SERIAL宏,在類實(shí)現(xiàn)中使用IMPLEMENT_SERIAL宏。我們看一下這兩個(gè)宏實(shí)現(xiàn)了什么,

            #define DECLARE_SERIAL(class_name) \
             _DECLARE_DYNCREATE(class_name) \
             AFX_API friend CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb);

            #define IMPLEMENT_SERIAL(class_name, base_class_name, wSchema) \
             CObject* PASCAL class_name::CreateObject() \
              { return new class_name; } \
             _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, \
              class_name::CreateObject) \
             AFX_CLASSINIT _init_##class_name(RUNTIME_CLASS(class_name)); \
             CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb) \
              { pOb = (class_name*) ar.ReadObject(RUNTIME_CLASS(class_name)); \
               return ar; } \

            主要是加入了對(duì)>>的重載,但是沒(méi)有重載<<,MFC僅提供了CObject對(duì)<<的重載,如下,

            _AFX_INLINE CArchive& AFXAPI operator<<(CArchive& ar, const CObject* pOb)
             { ar.WriteObject(pOb); return ar; }

            這是因?yàn)樵谛蛄谢x和寫的時(shí)候,都需要具體類的CRuntimeClass信息。相應(yīng)的GetRuntimeClass()是一個(gè)虛函數(shù),CObject重載<<,在寫類信息時(shí)調(diào)用到該函數(shù),由于虛函數(shù)機(jī)制,寫入的是具體類的信息。但是這里隱含著一個(gè)條件,就是調(diào)用<<和GetRuntimeClass()時(shí),具體類對(duì)象已經(jīng)存在了,而調(diào)用>>和讀入類信息時(shí),該類對(duì)象還未被創(chuàng)建,所以無(wú)法利用這種機(jī)制,只能在每個(gè)具體類中都重載一次>>。我覺(jué)得《深入解析MFC》對(duì)這個(gè)問(wèn)題的解釋不正確。

            這里有一個(gè)問(wèn)題需要明確一下,序列化為什么要寫入類信息?一是它應(yīng)該保存完整的能夠獨(dú)立恢復(fù)對(duì)象的信息,二是在程序讀入對(duì)象時(shí),要把它的類信息和程序中期望的(所能處理的)類信息相比較,進(jìn)行檢驗(yàn)。

            看IMPLEMENT_SERIAL宏對(duì)重載>>的實(shí)現(xiàn),是提供一個(gè)期望的CRuntimeClass結(jié)構(gòu)(用于檢驗(yàn)),委托CArchive進(jìn)行對(duì)象讀取。因?yàn)樽x對(duì)象時(shí)首先要跟文件打交道,所以交給CArchive處理,隨后把讀出的數(shù)據(jù)寫入對(duì)象時(shí),CArchive再調(diào)用具體類的Serialize(),如此合作是十分恰當(dāng)?shù)摹T谶@里,CArchive還負(fù)責(zé)了讀出和檢驗(yàn)類信息,然后創(chuàng)建對(duì)象的過(guò)程。因?yàn)橐环矫婢唧w類對(duì)象還不存在,另一方面這些操作對(duì)所有具體類都沒(méi)有分別,應(yīng)該提出來(lái),在類級(jí)別實(shí)現(xiàn)或者讓合作者實(shí)現(xiàn)。實(shí)際上,MFC先把這個(gè)過(guò)程交給CArchive::ReadClass(),后者又調(diào)用CRuntimeClass::Load()。 

            對(duì)于序列化來(lái)說(shuō),搞清它的概念以后,就是實(shí)現(xiàn)Serialzie(),重載<<和>>。對(duì)<<和>>的重載涉及很多工作,MFC已經(jīng)幫我們實(shí)現(xiàn)了,我們也看見(jiàn)了大概的設(shè)計(jì),主要是與CArchive分工合作,其次是CRuntimeClass。

            現(xiàn)在看到CRuntimeClass結(jié)構(gòu)體在MFC對(duì)RTCI,動(dòng)態(tài)創(chuàng)建和序列化的實(shí)現(xiàn)中都起著重要的作用,重新認(rèn)識(shí)一下這個(gè)數(shù)據(jù)結(jié)構(gòu)很有必要。

            CRuntimeClass包含了關(guān)于類的各種信息和有關(guān)操作。把類及其基類的CRuntimeClass連成一個(gè)鏈表,就可以很方便地實(shí)現(xiàn)RTCI的IsKindOf();把所有類的CRuntimeClass連成一個(gè)鏈表,再加上一個(gè)簡(jiǎn)單的CreateObject函數(shù),就可以對(duì)以任意類名進(jìn)行動(dòng)態(tài)創(chuàng)建的企圖做出反應(yīng);CRuntimeClass還實(shí)現(xiàn)了向文件讀寫類信息的Load(),Store(),配合序列化的實(shí)現(xiàn)。

            在分析消息映射和命令傳遞機(jī)制之前,需要對(duì)Windows程序模型有很好的理解。

            未完待續(xù)...


            參考:

            《深入解析MFC》/中國(guó)電力出版社
            《深入淺出MFC》/華中科大出版社
            《Windows程序設(shè)計(jì)》/北大出版社

            posted @ 2006-05-15 19:33 依舊的博客 閱讀(1152) | 評(píng)論 (0)編輯 收藏

            欣賞好的思路是一件愉快的事,特別是對(duì)我不會(huì)做的題目。

            1. 問(wèn)題:對(duì)32位的二進(jìn)制整數(shù),不用循環(huán),求出其中1的個(gè)數(shù)。

            #define?POW(c)?(1<<(c))
            #define?MASK(c)?(((unsigned?long)-1)?/?(POW(POW(c))?+?1))
            #define?ROUND(n,?c)?(((n)?&?MASK(c))?+?((n)?>>?POW(c)?&?MASK(c)))

            int?bit_count(unsigned?int?n)
            {
            ????n?
            =?ROUND(n,?0);
            ????n?
            =?ROUND(n,?1);
            ????n?
            =?ROUND(n,?2);
            ????n?
            =?ROUND(n,?3);
            ????n?
            =?ROUND(n,?4);
            ????
            return?n;
            }

            基本的想法是把所有的1加起來(lái),得到的就是1的個(gè)數(shù)。我們需要把這些1分離出來(lái),每個(gè)1都是平等的,與其位置無(wú)關(guān)。難題在于不能一個(gè)一個(gè)去取,那就用到了循環(huán),當(dāng)然遞歸也是不允許的。需要有一種統(tǒng)一的辦法,可是很難想象具體該怎樣。我們逐步地做這件事,假設(shè)前16位和后16位分別求得了1的個(gè)數(shù),那么加起來(lái)就行了。16位二進(jìn)制中的1仍然是未知的,隨機(jī)出現(xiàn)的,問(wèn)題的性質(zhì)沒(méi)有變,但我們可以繼續(xù)分解,這種逐步的做法不一定就意味著遞歸。每個(gè)16位分解為兩個(gè)8位,...,每個(gè)2位分解為兩個(gè)1位,把兩個(gè)1位上的數(shù)相加就是這兩位上1的個(gè)數(shù)。現(xiàn)在需要取出每一位上的數(shù)嗎?如果想到了這個(gè)問(wèn)題,就離最終的思路不遠(yuǎn)了。現(xiàn)在32位已經(jīng)分成了16個(gè)兩位,很容易將其看作兩個(gè)16位,一個(gè)是所有奇數(shù)位,一個(gè)是所有偶數(shù)位。我們不難把這兩個(gè)16位分開,然后移位相加,就求出了每?jī)晌恢?的個(gè)數(shù)。到了這一步,以后的思路就很自然了。


            參考:

            《計(jì)算二進(jìn)制位'1'的個(gè)數(shù)》來(lái)自?http://kaikai.cnblogs.com
            posted @ 2006-05-12 23:14 依舊的博客 閱讀(664) | 評(píng)論 (2)編輯 收藏

            僅列出標(biāo)題
            共2頁(yè): 1 2 
            国产三级精品久久| 久久超碰97人人做人人爱| 国产高潮久久免费观看| 国产精品99久久不卡| 亚洲国产天堂久久久久久| 久久精品桃花综合| 青青草国产精品久久| 久久综合伊人77777| 热re99久久精品国99热| 91精品国产91久久久久久蜜臀| 久久久久国产精品三级网| 久久久久久国产精品无码下载| 久久久久综合网久久| 久久久久亚洲AV无码观看| 久久综合九色综合久99| 精品久久久久久国产| 一本一道久久a久久精品综合| 99热成人精品热久久669| 亚洲综合精品香蕉久久网| 午夜精品久久久久久久无码| 91亚洲国产成人久久精品网址| 久久亚洲精品成人AV| 国内精品久久国产| 欧美伊人久久大香线蕉综合69| 草草久久久无码国产专区| 999久久久免费精品国产| 久久久久99精品成人片欧美 | 久久亚洲精品人成综合网| 久久最新免费视频| 久久青青国产| 久久人妻少妇嫩草AV无码蜜桃| 国产精品九九久久精品女同亚洲欧美日韩综合区| 一本综合久久国产二区| 亚洲国产精品狼友中文久久久| 久久久久亚洲AV成人网人人软件| 青青青青久久精品国产| 一本一道久久精品综合| 国产亚洲婷婷香蕉久久精品| 亚洲一本综合久久| 精品久久久久久国产免费了| 天天影视色香欲综合久久|