常數(shù)與運(yùn)行時(shí)類型信息編程_第1頁
常數(shù)與運(yùn)行時(shí)類型信息編程_第2頁
常數(shù)與運(yùn)行時(shí)類型信息編程_第3頁
常數(shù)與運(yùn)行時(shí)類型信息編程_第4頁
常數(shù)與運(yùn)行時(shí)類型信息編程_第5頁
已閱讀5頁,還剩24頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、第5章 集合、常數(shù)與運(yùn)行時(shí)類型信息編程定義好的抽象,可以解決許多編程方面的障礙。在面向?qū)ο笳Z言中,所謂的抽象就是“創(chuàng)建類”。在某種程度上確實(shí)如此。許多項(xiàng)目的失敗就是因?yàn)閯?chuàng)建的類太少,結(jié)果形成了一些龐大的類,它們做的事情太多,因而難于維護(hù)。好的抽象也可以在較低層次上定義。像Delphi這樣的強(qiáng)類型化編譯器、定義在問題域中有具體意義的類型等,都可能是有幫助的。一般的,進(jìn)行較為精確的類型定義,通??梢愿玫囟x類的屬性。大多數(shù)屬性的特征可以通過整數(shù)和數(shù)組進(jìn)行表達(dá),但相比而言,由內(nèi)建類型派生而來的集合、范圍、常數(shù)、數(shù)組以及枚舉等更有意義。Object Pascal是一種具有很強(qiáng)的表達(dá)能力的面向?qū)ο缶幊?/p>

2、語言,它有助于定義在特定問題域的上下文中具有意義的類型。例如,如果只有某個(gè)特定范圍內(nèi)的值有意義,就定義范圍、集合或枚舉類型來命名這些值所代表的數(shù)據(jù)。本章示范了如何使用Object Pascal中的這些概念,以有助于定義好的抽象。這些技術(shù)可以使您的代碼具有更強(qiáng)的可讀性,而且比使用內(nèi)建數(shù)據(jù)類型所需的錯(cuò)誤檢查代碼要少。5.1 不可變常數(shù)常數(shù)很好用。常數(shù)是現(xiàn)存的最為可靠的代碼之一。定義常數(shù)之后,無論如何其值都是可以依賴的。不用擔(dān)心,不存在偶然或有意的誤用。在Delphi中有許多方法來使用常數(shù),以使得代碼更加可靠。注意:Delphi支持類型化常數(shù),它們的值是可變的。關(guān)于可賦值的常數(shù),更多的信息請(qǐng)參見5.

3、1.3節(jié)“使用const創(chuàng)建靜態(tài)本地變量”。5.1.1 全局與本地常數(shù)當(dāng)變量定義在本地作用域中時(shí),可以訪問該作用域的代碼均可使用該變量。臨時(shí)使用全局或本地變量可能導(dǎo)致有害的問題,特別是對(duì)于多線程應(yīng)用程序,其中一個(gè)線程可能依賴于某個(gè)值,而另外一個(gè)線程正在改變?cè)撝?。如果一個(gè)值需要保持不變,則應(yīng)該用const來表示。全局常數(shù)是定義在單元的接口部分的常數(shù)。而本地常數(shù)是定義在實(shí)現(xiàn)部分的常數(shù)。另外,可能會(huì)在許多地方重用的值應(yīng)該定義為常數(shù)。假定Pi的值在您的整個(gè)程序中都是有意義的,則應(yīng)在接口部分將名字Pi作為常數(shù)引入,并將其值初始化為具有正確的有效數(shù)字位數(shù)的Pi值,以滿足您的需要。注意:新的單元ConvUt

4、ils.pas包含有數(shù)以百計(jì)的常數(shù)和轉(zhuǎn)換單元。盡管它包含了秒差距與米的轉(zhuǎn)換常數(shù)值,但并未包含Pi的常數(shù)值。System.pas單元中包含了函數(shù)Pi,返回Pi值的extended類型的浮點(diǎn)值。我們的目標(biāo)是在盡可能狹窄的作用域中定義常數(shù)。如果一個(gè)常數(shù)只在過程塊中需要,那么該過程就是合適的作用域。使作用域變窄背后的思想在于,要盡量減少使用代碼的程序員在理解代碼目的時(shí)所需要進(jìn)行思考的事物的數(shù)目。常數(shù)的語法部分依賴于其所定義的上下文。本地、全局、過程常數(shù)的通常形式如下:const name = value;或,const name : type = value;const是關(guān)鍵字,表示其后是常數(shù)。對(duì)于一

5、個(gè)常數(shù)列表中的所有常數(shù),僅需要鍵入const一次。例如,在實(shí)現(xiàn)部分定義三個(gè)常數(shù),如下所示。implementationconstI : Integer = 3;S = 'Bachman Turner Overdrive'F : Double = 4000000000000.0;有許多途徑來使用常數(shù),可以使得程序更加可靠。對(duì)于常數(shù)的所有變體的語法規(guī)則,請(qǐng)察看上下文幫助,在索引中查找grammar。更多的例子見下文。5.1.2 常數(shù)參數(shù)當(dāng)過程不應(yīng)改變某個(gè)參數(shù)的值時(shí),應(yīng)把該參數(shù)聲明為常數(shù)參數(shù)。如果包括了const限定符,可以保證該值不被改變。保證總是難于得到,因此能夠得到保證確實(shí)不錯(cuò)

6、。常數(shù)參數(shù)可以有默認(rèn)值。下面的代碼演示了具有默認(rèn)值的常數(shù)參數(shù)。procedure DisplayBandName( const Value : String = 'R.E.O.' );beginShowMessage( Value );end;Procedure SomeProc;constBTO = 'Bachman Turner Overdrive'beginDisplayBandName;end;DisplayBandName過程中定義了一個(gè)具有默認(rèn)值的參數(shù)。如果不傳遞參數(shù),Value參數(shù)的值將是R.E.O.。如果把常數(shù)BTO傳遞給DisplayBandN

7、ame,那么ShowMessage函數(shù)將顯示Bachman Turner Overdrive。常數(shù)參數(shù)的存在保證了調(diào)用的方法不會(huì)在無意中改變傳遞的參數(shù)值。使用const要遠(yuǎn)勝于希望和祈禱。5.1.3 使用const創(chuàng)建靜態(tài)本地變量定義在過程中的變量在棧上分配內(nèi)存空間。常數(shù)通過編譯嵌入到代碼中,只存在于所定義的過程中。當(dāng)過程調(diào)用或退出時(shí),棧內(nèi)存空間像手風(fēng)琴一樣來回伸縮。通常,在過程中引入的名字具有過程作用域。即,該名字和值只在所定義的作用域中可訪問。有時(shí),您可能需要各種占位符,即只在過程作用域可訪問的名字,而在過程返回后依然保持其值。C和C+稱之為靜態(tài)變量。Delphi用可賦值常數(shù)來產(chǎn)生同樣的效

8、果。使用下面的語法您可以定義一個(gè)變量,它看上去是常數(shù),但實(shí)際上是可變的靜態(tài)變量。Procedure MutableConst;constI : Integer = 0;beginInc(I);ShowMessage(IntToStr(I);end;/ .for I := 0 to 3 do MutableConst;在上面的MutableConst過程中定義一個(gè)類型化的可賦值常數(shù),常數(shù)的值在該過程的各次調(diào)用之間仍然可以保持。最后一行的for語句調(diào)用MutableConst四次,最后一次調(diào)用在ShowMessage的對(duì)話框中顯示值為4。默認(rèn)情況下,類型化常數(shù)是可賦值的??梢酝ㄟ^$J+編譯器指令進(jìn)

9、行改變;或者在Project Options對(duì)話框中的Compiler屬性頁中改變Assignable typed constants復(fù)選框,如圖5.1所示。圖5.1 默認(rèn)情況下,類型化常數(shù)是可賦值的,并且可以在對(duì)其所定義的過程的后續(xù)調(diào)用之間維持其值。要使其不可賦值,對(duì)Project Options對(duì)話框中的Compiler屬性頁的Assignable typed constants復(fù)選框取消選定即可。默認(rèn)情況下,該復(fù)選框是選定的可賦值類型化常數(shù)使得可以在過程中定義占位符,每次該過程調(diào)用時(shí)都可以維護(hù)該值。通過使用可賦值類型化常數(shù),可以模擬靜態(tài)特性(有關(guān)靜態(tài)特性的更多知識(shí),請(qǐng)閱讀第7章)。5.1

10、.4 數(shù)組常數(shù)對(duì)您的武器庫來說,數(shù)組常數(shù)是另外一項(xiàng)可以添加的工具。也許您不會(huì)每天都用到數(shù)組常數(shù),但在日常編程中確實(shí)有一些數(shù)組常數(shù)的例子。考慮下列例子。Procedure ArrayExamples;constDaysOfWeek : array1.7 of string = ('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' );MonthsOfYear : array1.12 o

11、f string = ('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August','September', 'October', 'November', 'December' );EXAMPLE1 = 'February 12, 1966 occurred on a %s'EXAMPLE2 = '

12、;The fourth month is %s'varOutput : string;Day : Integer;beginDay := DayOfWeek( StrToDate('02/12/1966');Output := Format( EXAMPLE1, DaysOfWeekDay );ShowMessage( Output );Output := Format( EXAMPLE2, MonthsOfYear4 );ShowMessage(Output);end;DaysOfWeek數(shù)組包含了7個(gè)元素,都是字符串。MonthsOfYear數(shù)組包含了12個(gè)元素,也

13、都是字符串。兩個(gè)數(shù)組都初始化為常數(shù)數(shù)組。Begin塊語句的第2行使用星期中某天對(duì)應(yīng)的數(shù)字來索引數(shù)組。第1次調(diào)用ShowMessage過程的輸出為February 12, 1966 occurred on a Saturday。Begin塊語句的第4行對(duì)該年的月份執(zhí)行了一個(gè)簡(jiǎn)單的操作。當(dāng)然您也可以把上面的代碼寫成由嵌套if條件測(cè)試組成的case語句,但常數(shù)數(shù)組在緊湊的操作中生成了優(yōu)化而更小的代碼??紤]下一個(gè)例子,其中用if條件測(cè)試來比較激活狀態(tài)以設(shè)置控件的背景顏色,也提供了用數(shù)組實(shí)現(xiàn)的相同功能的代碼。if( Edit1.Enabled = False ) thenbeginEdit1.Enabl

14、ed := True;Edit1.Color := clWhite;endelse / TruebeginEdit1.Enabled := False;Edit1.Color := clBtnFace;end;上面的代碼計(jì)算了TEdit控件(隨機(jī)選定)的Enabled狀態(tài),對(duì)該狀態(tài)取反,并相應(yīng)地設(shè)置顏色。該代碼實(shí)用而直接,但使用常數(shù)數(shù)組可使之更為有效。使用常數(shù)數(shù)組的修訂版本如下。constColors : arrayBoolean of TColor = (clBtnFace, clWhite);beginEdit1.Enabled := Not Edit1.Enabled;Edit1.Col

15、or := ColorsEdit1.Enabled;end;常數(shù)數(shù)組使得我們可以將代碼縮減到原來的五分之一。使用單目not操作符來執(zhí)行Enabled狀態(tài)的切換,用Enabled特性的布爾值來索引常數(shù)數(shù)組Colors。在使用布爾值作索引時(shí),F(xiàn)alse的值較小。上面的代碼更加緊湊,既小且快。下一節(jié)的內(nèi)容是有關(guān)記錄常數(shù)的,閱讀時(shí)請(qǐng)注意其中一個(gè)用到記錄數(shù)組常數(shù)的例子。5.1.5 記錄常數(shù)記錄常數(shù)是類型為記錄的常量數(shù)據(jù)。一個(gè)很普遍的記錄是TPoint。TPoint在笛卡爾坐標(biāo)系中定義了兩個(gè)坐標(biāo)。TPoint在Windows.pas單元中如下定義:TPoint = recordx: Longint;y:

16、Longint;end;要初始化常量記錄,需要以fieldname : value的形式指定每個(gè)字段,每個(gè)字段的名字與值用冒號(hào)分隔。這里有一個(gè)例子。const Point : TPoint = (X:100; Y:100);常量記錄數(shù)組需要初始化每個(gè)數(shù)組元素,對(duì)于構(gòu)成記錄值的字段,將名字和值對(duì)的集合用括弧括起來。這里是一個(gè)由四個(gè)點(diǎn)構(gòu)成的數(shù)組。constPoints : array0.3 of TPoint = (X:10;Y:10), (X:10;Y:100), (X:100;Y:100), (X:100; Y:10);Procedure DrawRect( const Points : Ar

17、ray of TPoint );varI : Integer;beginCanvas.PenPos := Points0;for I := Low(Points) to High(Points) doCanvas.LineTo( PointsI.X, PointsI.Y );Canvas.LineTo( Points0.X, Points0.Y );end;由于并未考慮監(jiān)視器屏幕的高寬比,該數(shù)組只是粗略地定義了如圖5.2所示的正方形。數(shù)組Points被傳遞給代碼中的DrawRect過程,用以生成如圖5.2所示的正方形。圖5.2 利用LineTo方法和TPoint記錄組成的 數(shù)組,在窗體的畫布上

18、所畫出的正方形通過將一些基本的Object Pascal術(shù)語聯(lián)合起來,可以很容易地創(chuàng)建很多種常量數(shù)據(jù),用于代表各種各樣的信息。使用記錄和數(shù)組常數(shù),可以使您的代碼更具有表現(xiàn)力。通過把精確定義的數(shù)據(jù)映射到問題域的信息,對(duì)代碼控制得越好,管理數(shù)據(jù)所需的代碼就越少。5.1.6 過程常數(shù)過程常數(shù)是用const修飾的名字,其數(shù)據(jù)類型為過程類型。一般來說,過程類型只是指向過程的指針,它使得可以把過程和函數(shù)賦值給類型與其相匹配的變量和參數(shù)。過程類型的更多知識(shí)可以閱讀第6章。一個(gè)過程類型的例子就是定義在classes.pas單元中的TNotifyEvent。下面是classes.pas的摘錄,給出了TNotif

19、yEvent的定義。type TNotifyEvent = procedure (Sender: TObject) of object;從列出的代碼可以看出,TNotifyEvent類型是由過程組成的,它們有一個(gè)TObject類型的參數(shù),名字為Sender。類型定義結(jié)尾的of object表示TNotifyEvent類型是被稱為方法指針的特定過程類型。TNotifyEvent看起來很熟悉,因?yàn)樗褪荗bject Inspector中許多事件特性的類型。雙擊空白窗體,Delphi將為窗體的OnCreate事件特性創(chuàng)建如下的空方法定義。procedure TForm1.FormCreate(Sen

20、der: TObject);beginend;注意:按照慣例,Delphi使用On前綴表示該特性為事件特性。On暗示著對(duì)動(dòng)作的響應(yīng),即事件。代碼中的TForm1.部分表示該方法屬于TForm1類。FormCreate表示它是OnCreate事件的處理程序,將類名和方法名從定義中剝離,余下的就是procedure (Sender:TObject),恰好可以與TNotifyEvent匹配。在Delphi中選擇OnCreate事件特性,按鍵F1,將顯示CustomForm.OnCreate的上下文幫助。幫助文檔清楚地指出,OnCreate定義為特性O(shè)nCreate : TNotifyEvent; 即

21、類型為TNotifyEvent的特性。5.1.7 指針常數(shù)無論使用任何語言,我們的思維都只是受限于用以表達(dá)思想的語言以及我們對(duì)它掌握的熟練程度。一些術(shù)語可能不像其余的那樣常用。指針常量就是其中的一個(gè)。在日常的Windows應(yīng)用編程中,指針可能不太常用,不過Delphi并不限制您只能編寫典型的Windows風(fēng)格的程序。指針常量就是指向特定地址的指針。下面的代碼瑣碎而令人困惑,但它演示了與指針常量有關(guān)的必要機(jī)制。typeTDateTimeFunc = function : TDateTime;constNowP : Pointer = SysUtils.Now;varMyNow : TDateTi

22、meFunc absolute NowP;第2行定義了一個(gè)過程類型,它是指向函數(shù)的指針,返回TDateTime值。常量指針被初始化為SysUtils.pas中定義的Now函數(shù)地址。變量MyNow類型為TDateTimeFunc(在類型部分定義),將編譯為SysUtils.Now函數(shù)的絕對(duì)地址。5.1.8 用于初始化常量的過程在前面關(guān)于過程常數(shù)的章節(jié)中,您已經(jīng)知道過程類型可用于定義常數(shù)并初始化為某一特定的過程。對(duì)于前一節(jié)中的例子,無須使用Pointer即可定義對(duì)SysUtils.Now函數(shù)的常量引用。typeTDateTimeFunc = function : TDateTime;constCo

23、nstNow : TDateTimeFunc = SysUtils.Now;調(diào)用ConstNow與調(diào)用SysUtils.Now具有相同的效果。由于Delphi支持過程類型,因此用這種形式定義指向過程的變量或常數(shù)更為可取。無論對(duì)于哪種類型,均可使用Pointer來指向一個(gè)特定的內(nèi)存地址。5.2 枚舉的使用枚舉是代表值的名字列表。如果使用枚舉更有意義,那么它比內(nèi)建數(shù)據(jù)類型更為可取。枚舉的一個(gè)完美的例子是TFontStyle。有四種基本的字體風(fēng)格:黑體、斜體、加下劃線的、加刪除線的。很清楚,可以用整數(shù)來存儲(chǔ)字體風(fēng)格的狀態(tài),但對(duì)特定風(fēng)格進(jìn)行列表更有意義。graphics.pas單元如下定義了TFont

24、Style類型。type TFontStyle = (fsBold, fsItalic, fsUnderline, fsStrikeOut);定義TFontStyle使得程序員可以聲明TFontStyle類型的變量,保證了所有賦予TFontStyle類型變量的值都是有效的,而且不必進(jìn)行訪問檢查和錯(cuò)誤檢查。由于編譯器是強(qiáng)類型的,只有四個(gè)可能值之一才能賦予TFontStyle變量。簡(jiǎn)言之,所有困難的工作都由編譯器來做,因而代碼對(duì)于程序員更加可讀。5.2.1 用枚舉定義數(shù)組邊界按照經(jīng)驗(yàn)規(guī)則,相對(duì)于原始的數(shù)組,TList和TCollection更為可取。回顧使用對(duì)象而不是數(shù)組來存儲(chǔ)數(shù)據(jù)的原因:表和集合

25、類可以動(dòng)態(tài)地伸縮,其中包括了范圍檢查及其他一些功能,如排序和查找等。使用數(shù)組則需要實(shí)現(xiàn)所有這些功能。有些情況下,您可能需要使用數(shù)組。除去索引范圍檢查的一種方法是:使用枚舉作為索引的類型,從而使數(shù)據(jù)的范圍精確化。這里有一個(gè)例子演示了TNote類型,它使用Windows API函數(shù)Beep來播放一個(gè)音符(音符的頻率和長(zhǎng)短是模擬的)。typeTNote = (doDo, doRe, doMi, doFa, doSo, doLa, doTi, doDo2 );Procedure PlayNote( Note : TNote );constDoReMi : arrayTNote of Integer =

26、 (500, 600, 700, 800, 900, 1000, 1100, 1200 );beginWindows.Beep( DoReMeNote, 750 );Sleep(250);end;Procedure PlayNotes;varI : TNote;beginfor I := Low(TNote) to High(TNote) doPlayNote( I );end;第二行定義了一個(gè)枚舉類型TNote,包含八個(gè)元素。PlayNote過程使用Low和High函數(shù)得到值的范圍,然后對(duì)每個(gè)元素進(jìn)行迭代??梢宰⒁獾剿饕齀定義為TNote類型而不是整數(shù)。每次循環(huán)時(shí),都以當(dāng)前枚舉值為參數(shù)調(diào)用P

27、layNote過程。PlayNote過程參數(shù)為TNote類型,過程中定義了一個(gè)索引為TNote類型的常量數(shù)組,并使用Windows API函數(shù)Beep(并非Delphi所提供的版本)來播放每個(gè)音符對(duì)應(yīng)的頻率。請(qǐng)注意并不需要范圍檢查,因?yàn)閷?duì)于數(shù)組DoReMi,所有可能的TNote值都是可行的,因?yàn)樗鼈兌际艿矫杜e范圍的限制。定義枚舉和其他精確化的類型具有累積效應(yīng)。需要調(diào)試和測(cè)試的代碼會(huì)逐漸減少,您的代碼將更有效地運(yùn)行。5.2.2 預(yù)定義枚舉類型有許多預(yù)定義的枚舉類型,實(shí)際上,枚舉類型太多以至于無法全部涵蓋。這種類型的參考手冊(cè)最好留給在線幫助文檔去作。如果您已經(jīng)習(xí)慣于用以控制組件行為的枚舉類型,就可

28、以更加出色地控制VCL。以TControlStyle為例。所有的控件都具有ControlStyle特性,該類型定義為枚舉值的集合(有關(guān)集合操作和定義,更多的信息請(qǐng)參見下一節(jié))。type TControlStyle = set of (csAcceptsControls, csCaptureMouse, csDesignInteractive, csClickEvents, csFramed, csSetCaption, csOpaque, csDoubleClicks, csFixedWidth, csFixedHeight, csNoDesignVisible, csReplicatable

29、, csNoStdEvents, csDisplayDragImage, csReflector, csActionClient, csMenuEvents);ControlStyle特性可以具有零個(gè)、一個(gè)或多個(gè)定義在上述枚舉中的值。例如,如果ControlStyle具有csAcceptsControls值,則該控件就可以擁有其他的控件。例如窗體可以擁有控件,但默認(rèn)情況下,柵格控件是無法擁有其他控件的。對(duì)于已有的控件,其行為是由作者定義的。但您總是可以子類化一個(gè)控件,根據(jù)您的需要調(diào)整其行為。例如,下面的類定義了TControlGrid類型,示范了如何在柵格單元中擁有其他控件(如圖5.3所示)。

30、圖5.3 可以在柵格單元中擁有其他控件的柵格控件TControlGrid = class(TStringGrid)privateFButton : TButton;protectedProcedure WMCommand( var Message : TWMCommand ); Message WM_COMMAND;Procedure OnClick( Sender : TObject );Procedure Paint; override;publicconstructor Create( AComponent : TComponent); override;destructor Destr

31、oy; override;end;注意:如果在設(shè)計(jì)時(shí)可以在柵格上繪制出控件,TControlGrid類就可以更有用。使用上面以及下面列出的代碼,即可完成該柵格控件,從而可以在設(shè)計(jì)時(shí)和運(yùn)行時(shí)動(dòng)態(tài)地?fù)碛锌丶?。關(guān)于柵格組件的演示,參見該類包含一個(gè)private字段FButton,用于示范擁有控件的功能。protected message方法重載了WM_COMMAND的信息處理程序。這使得被擁有的控件可以接收到發(fā)送給它們的消息,但TStringGrid并未如此,因?yàn)樵谠瓉淼脑O(shè)計(jì)中TStringGrid是無法擁有父控件的。OnClick事件處理程序用于演示TButton控件對(duì)用戶輸入的響應(yīng)。構(gòu)造函數(shù)和析

32、構(gòu)函數(shù)中重載了ControlStyle特性,并對(duì)TButton控件進(jìn)行分配和釋放。 TControlGrid constructor TControlGrid.Create(AComponent: TComponent);begininherited Create(AComponent);ControlStyle := ControlStyle + csAcceptsControls;FButton := TButton.Create(Self);FButton.Parent := Self;FButton.BringToFront;FButton.OnClick := OnClick;Rep

33、aint;end;Procedure TControlGrid.Paint;begininherited Paint;FButton.Visible := (LeftCol = 1) and (TopRow = 1);FButton.Enabled := FButton.Visible;FButton.BoundsRect := CellRect( 1, 1 );end;destructor TControlGrid.Destroy;beginFButton.Free;inherited;end;procedure TControlGrid.OnClick(Sender: TObject);b

34、eginMessageDlg('Greetings Earthlings!', mtInformation, mbOK, 0);end;Procedure TControlGrid.WMCommand( var Message : TWMCommand );begininherited;if( ControlCount > 0 ) thenFindControl( Message.Ctl ).Dispatch(Message);end;構(gòu)造函數(shù)ControlGrid調(diào)用TStringGrid的構(gòu)造函數(shù),創(chuàng)建按鈕,并為按鈕的OnClick事件設(shè)置處理程序。Paint方法被重

35、載,用于在單元1中繪制該單元的控件(1單元可見時(shí))。對(duì)于動(dòng)態(tài)的控件,跟蹤該控件屬于哪一個(gè)單元是必要的。析構(gòu)函數(shù)釋放了按鈕,并調(diào)用TStringGrid的析構(gòu)函數(shù)。當(dāng)單擊按鈕時(shí),OnClick方法將顯示友好的問候。最后,WMCommand方法響應(yīng)所有的消息,首先調(diào)用繼承的消息處理程序,然后對(duì)擁有的控件分發(fā)消息(消息處理程序的更多知識(shí)請(qǐng)閱讀第6章)。在逐漸掌握Delphi的體系結(jié)構(gòu)之后,無論編寫簡(jiǎn)單或還是復(fù)雜的控件,都可以利用已有類的屬性進(jìn)行簡(jiǎn)化,這樣可以使程序更加靈活、實(shí)用。5.2.3 用于枚舉類型的過程有一些函數(shù)是專門設(shè)計(jì)用于枚舉類型的。表5.1列出用于枚舉類型的過程,并描述了每個(gè)過程所執(zhí)行的

36、操作。表5.1 用于枚舉類型的過程過程描述Ord返回整數(shù),表示與其位置相關(guān)的枚舉值Pred返回在傳給函數(shù)的值之前的枚舉值Succ返回傳給函數(shù)的值的下一個(gè)枚舉值High返回最大的枚舉值Low返回最小的枚舉值枚舉是有序類型,基于在類型定義中的出現(xiàn)次序,枚舉元素自動(dòng)地分配連續(xù)值,從第一個(gè)位置的0開始到最后一個(gè)位置的n-1結(jié)束。例如,可以使用High和Low函數(shù)得到枚舉的上界和下界。如果包含了運(yùn)行時(shí)類型信息(RTTI),則枚舉的符號(hào)名也可以得到。下面列出的程序演示所有的五個(gè)枚舉函數(shù),以及如何包含RTTI信息。uses typinfo;$M+typeTEnums = ( Enum0, Enum1, En

37、um2, Enum3, Enum4);$M-procedure ShowEnum( Enum : TEnums );constMASK = '%s=%d'varName : String;Value : Integer;beginName := GetEnumName( TypeInfo(TEnums), Ord(Enum) );Value := GetEnumValue( TypeInfo(TEnums), Name );ShowMessage( Format( MASK, Name, Value );end;procedure TestEnumerated;beginSho

38、wEnum( Enum3 );ShowEnum( Pred( Enum3 );ShowEnum( Succ( Enum3 );ShowMessage( IntToStr(Ord( Enum4 ) );ShowEnum( Low(TEnums);ShowEnum( High( TEnums );end;注意:盡管Delphi本身也使用了GetEnumName和GetEnumValue函數(shù),但由于某些原因,它們并未包括在上下文相關(guān)幫助中。RTTI用于特性的讀寫,以及OpenTools API(關(guān)于OpenTools API,請(qǐng)參考附錄A)。第一行的uses語句表示應(yīng)包括typinfo單元。該單元包

39、括了與運(yùn)行時(shí)類型信息相關(guān)的過程,其中就有在本例中用到的GetEnumName和GetEnumValue。第四行定義了枚舉類型TEnums,該定義包含在$M+和$M-編譯器指令之間。$M指令指示編譯器對(duì)TEnums類型加入運(yùn)行時(shí)類型信息。第六行開始的ShowEnum過程示范了如何使用typinfo.pas中所定義的GetEnumName和GetEnumValue過程。這兩個(gè)過程的第一個(gè)參數(shù)是指向TTypeInfo記錄的指針。如代碼所示,將枚舉類型的名字傳遞給TypeInfo函數(shù)將返回指向類型信息記錄的指針。GetEnumName中的第二個(gè)參數(shù)是枚舉類型中某個(gè)特定元素所對(duì)應(yīng)的有序數(shù)值。GetEnu

40、mValue則根據(jù)類型信息記錄和枚舉元素的名字返回對(duì)應(yīng)的有序數(shù)值。TestEnumerated過程的輸出如下:ShowEnum( Enum3 ); / outputs Enum3=3ShowEnum( Pred( Enum3 ); / outputs Enum2=2ShowEnum( Succ( Enum3 ); / outputs Enum4=4ShowMessage( IntToStr(Ord( Enum4 ) ); / outputs 4ShowEnum( Low(TEnums); / outputs Enum0=0ShowEnum( High( TEnums ); / outputs

41、Enum4=4某些低層的VCL過程使用了運(yùn)行時(shí)類型信息。在創(chuàng)建組件和枚舉時(shí),運(yùn)行時(shí)類型信息特別有用。枚舉可以使代碼更加健壯、富于表現(xiàn)力、可讀性好。5.3 集 合 操 作集合通常表示一組相關(guān)的事物,如一組塔珀家用塑料制品或一組高爾夫球棍。集合操作是人類最早了解的數(shù)學(xué)知識(shí)之一(至少在美國和西歐是這樣)。至少有三十年了,Sesame Street一直教著這首歌“Which one of these things is not like the other? Which one of these things just doesnt belong?”即,哪些是集合的成員而哪些不是?集合在實(shí)際的世界中是

42、很常見的,因此,很自然的,在抽象世界中應(yīng)存在這樣的術(shù)語,使得開發(fā)者可以表達(dá)集合的概念并對(duì)其進(jìn)行算術(shù)操作。在Object Pascal中確實(shí)如此,我們只需將自己的理解映射到Delphi中的集合實(shí)現(xiàn)即可。5.3.1 理解集合以及set of語句集合是同一有序類型的值的聚集。集合的例子有:所有整數(shù)的集合、某個(gè)枚舉類型中所有元素的集合或彩虹中所有元素的集合。在Object Pascal中的集合的大小限定到一個(gè)字節(jié),這意味著一個(gè)特定集合的基類型必須限制到少于256個(gè)元素,而其有序值必須在0到255之間。集合的值的范圍是其基類型的冪集,冪集就是包括空集在內(nèi)一個(gè)集合的所有可能的子集的集合。定義集合的語法是:

43、SetType -> SET OF OrdinalType,其中OrdinalType定義為:OrdinalType -> (SubrangeType | EnumeratedType | OrdIdent)。就是說,集合定義在單元的類型部分,將一個(gè)名字與子界類型、枚舉類型或有序類型的集合聯(lián)系起來即可。OrdinalType所涉及的各種類型示范如下。TRangeSet = set of 0.255;TCharSet = set of char;TPrimaryColors = set of (pcRed, pcBlue, pcGreen);TRangeSet示范了一個(gè)由整數(shù)構(gòu)成的子

44、界集合,其值由0到255。TCharSet定義了由三原色構(gòu)成的枚舉值的集合。定義集合類型后,則集合實(shí)例都是一些子集,其中包含了一些該類型的元素。5.3.2 使用集合構(gòu)造器set of語句定義了一個(gè)類型,其中包括從某個(gè)有序類型而來的一個(gè)有限范圍內(nèi)的值。集合類型的變量可以是受類型定義約束的冪集的任一元素。要初始化集合類型的實(shí)例,可以使用集合構(gòu)造器。集合構(gòu)造器由 標(biāo)識(shí),其中包含一些由逗號(hào)或.分隔的值??紤]上一節(jié)的TCharSet集合。要構(gòu)造一個(gè)包含大寫字母的TCharSet變量,使用如下代碼即可。varUpperCaseChars : TCharSet;beginUpperCaseChars :=

45、'A'.'Z'/ .end;變量UpperCaseChars是TCharSet的一個(gè)子集,初始化時(shí)包含了所有的大寫字母。由于UpperCaseChars定義為變量,因此可以向集合添加成員。要使UpperCaseChars只包含大寫字母字符,可以將其定義為常數(shù)并使用$J-編譯器指令使該常量不可賦值,或者定義一個(gè)只包含大寫字母的集合類型。const$J-UpperCaseChars : TCharSet = 'A'.'Z'$J+或者typeTUpperCaseChars = set of 'A'.'Z'

46、提示:默認(rèn)情況下,Delphi中的類型化常數(shù)是可寫的。要限制UpperCaseChars只包含從A到Z的字母,可以重新定義集合類型或者把可寫類型化常數(shù)用編譯器指令包裹起來,如下所示:$J- const UpperCaseChars : TCharSet = 'A'.'Z' $J+?,F(xiàn)在,UpperCaseChars是個(gè)只包含字符A到Z的不可賦值的常數(shù),而TUpperCaseChars類型的范圍則限制為字符A到Z。可定義TUpperCaseChars類型的變量,例如:varUpperCaseChars : TUpperCaseChars;這樣UpperCaseCh

47、ars的值就隱含地限制到了從A到Z?;叵胍幌拢J(rèn)情況下Delphi中的類型化常數(shù)是可寫的(請(qǐng)參考上面的提示,其中簡(jiǎn)短地討論了對(duì)代碼的可能修改,從而使其目的性更強(qiáng))。為包括大寫字母和小寫字母,擴(kuò)展上面的集合構(gòu)造器以包含小寫字母。constAlphabeticChars : TCharSet = 'A'.'Z', 'a'.'z'現(xiàn)在TCharSet變量AlphabeticChars包含了所有大寫和小寫的字母字符。為簡(jiǎn)化集合代數(shù),有許多操作符可以執(zhí)行集合算術(shù)運(yùn)算。5.3.3 集合操作符表5.2包含了集合的算術(shù)操作符的完整列表,并描述了

48、對(duì)集合進(jìn)行的操作。所有的集合運(yùn)算,其結(jié)果或者為布爾值,或者為新的子集。表5.2 集合操作符與結(jié)果類型,除了in以外,所有的集合操作符的兩個(gè)操作數(shù)都是集合操作符操作結(jié)果例子+并集合Set1 + Set2-差集合Set1 Set2*交集合Set1 * Set2<=是的子集布爾值Set1 <= Set2>=是的超集布爾值Set1 >= Set2=相等布爾值Set1 = Set2<>不等布爾值Set1 <> Set2in是的成員布爾值Ordinal in Set1下面列出的代碼示范了對(duì)四個(gè)集合執(zhí)行的集合操作,它們都定義為字符集合的子集。typeTChar

49、Set = set of char;constA : TCharSet = 'A'.'M', 'R', 'S', 'U'B : TCharSet = 'B', 'G', 'H', 'L'.'Z'SubsetA : TCharSet = 'A'.'G'SupersetA : TCharSet = 'A'.'M', 'R', 'S', '

50、U', 'V'Procedure TForm1.DisplayResultset( OperationName : String; const CharSet : TCharSet );varI : Char;Count : Integer;beginMemo1.Lines.Add( '*' + OperationName + '*' );Count := 0;for I := Low(Char) to High(Char) doif( I in CharSet ) thenbeginMemo1.Lines.Add(I);Inc(Coun

51、t);end;Memo1.Lines.Add( '* Elem Count: ' + IntToStr(Count) + ' *' );end;Procedure TForm1.SetTests;constBOOLS : arrayBoolean of String = (' is False', ' is True' );beginMemo1.Clear;DisplayResultSet( 'union', A + B );DisplayResultSet( 'difference', A - B

52、 );DisplayResultSet( 'intersection', A * B );Memo1.Lines.Add( 'A < SubSetA (Not A >= SubSetA)' + BOOLS Not (A >= SubSetA) );Memo1.Lines.Add( 'A > SuperSetA (Not A <= SuperSetA)' + BOOLS Not (A <= SuperSetA) );Memo1.Lines.Add( 'A <= SupersetA' + BO

53、OLS A <= SuperSetA );Memo1.Lines.Add( 'A >= SubsetA' + BOOLSA >= SubSetA );Memo1.Lines.Add( 'A = B' + BOOLSA = B );Memo1.Lines.Add( 'A <> B' + BOOLSA <> B );Memo1.Lines.Add( '''A'' in B' + BOOLS 'A' in B );end;類型聲明部分定義了一個(gè)由字

54、符組成的集合類型。常數(shù)聲明部分包含了四個(gè)集合的定義,它們是字符集合的子集。集合A和B是不同的集合,SubsetA初始化為集合A的子集,而SuperSetA初始化為集合A的超集。DisplayResultSet方法使用in操作符來測(cè)試某個(gè)特定的字符是否是結(jié)果集合的成員。例子的輸出如下。· A與B的并集A+B是所有大寫字母字符的集合,因?yàn)樗械拇髮懽帜缸址蛘咴贏中或者在B中。· A與B的差集A-B包含字母A、C、D、E、F、I、J、K,因?yàn)锳的這些元素不是B的成員。B-A則得到一個(gè)不同的結(jié)果集合。· A與B的交集A*B包含字母B、G、H、L、M、R、S、U,因?yàn)锳和

55、B中均包含這些元素。· 如果SubSetA是A的子集,則用Not (A >= SubSetA)實(shí)現(xiàn)的A < SubSetA結(jié)果為False。· 如果SuperSetA是A的超集,則用Not (A <= SuperSetA)實(shí)現(xiàn)的A > SuperSetA結(jié)果為False。· A <= SuperSetA的結(jié)果為True,因?yàn)镾uperSetA中包含所有A中的元素以及V。· A >= SubSetA的結(jié)果也是True,因?yàn)镾ubSetA中只包含A的部分元素。· A = B結(jié)果為False,因?yàn)锳中的所有元素都不

56、在B中。· A <> B結(jié)果為True(見前一項(xiàng)條件測(cè)試A = B)。· 字符A不是集合B的成員,因此Ain B結(jié)果為False。對(duì)謂詞與命題的演算,定義了用于集合的邏輯操作和謂詞語句的代數(shù)規(guī)則。但不要假定用戶也上過離散數(shù)學(xué)的課程,應(yīng)該考慮把繁復(fù)的集合操作分解為對(duì)中間結(jié)果進(jìn)行運(yùn)算的單一的集合操作。集合代數(shù)演算基本的四個(gè)代數(shù)定律對(duì)集合邏輯也是適用的。這意味著集合具有傳遞性,即如果A = B而且 B = C則A = C;集合具有對(duì)稱性,即A = A;集合具有交換性(對(duì)集合的差不適用),即A + B = B + A;集合具有分配性,A * B + A * C = A

57、* ( B + C )。如果需要,可以用這四個(gè)基本的數(shù)學(xué)定律簡(jiǎn)化復(fù)雜的集合等式。下列代碼示范了集合的分配律、對(duì)稱律以及交換律,這些定律都是對(duì)基類型為byte的數(shù)集驗(yàn)證的。typeTSet = set of byte;constSet1 : TSet = 1, 2, 3, 4;Set2 : TSet = 3, 4, 5, 6;Set3 : TSet = 5, 6, 7, 8;procedure DisplayResult( ASet : TSet );varI : Byte;beginfor I := Low(Byte) to High(Byte) doif( I In ASet ) thenF

58、orm1.Memo1.Lines.Add( IntToStr(I);end;procedure SetTest;constBOOLS : arrayBoolean of string = ('False', 'True');varResultSet : TSet;begin/ Distributive Law/ ResultSet := (Set1 * Set3) + (Set2 * Set3);ShowMessage( BOOLS Set3 * (Set1 + Set2) = (Set3 * Set1) + (Set3 * Set2) );ResultSet := Set3 * (Set1 + Set2);DisplayResult( ResultSet );/ reflexive A + B = B + AShowMessage( BOOLSSet1 + Set2 = Set2 + Set1 )

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(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ì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論