资源描述
附錄 EDelphi 4 增訂的 Object Pascal本附錄在於說明Delphi 4新增訂的Object Pascal程式語言。總結來說,Delphi 4的Object Pascal增訂了以下幾大部分了:口新增加數種內定資料型態。 Dynamic Arrays Method and Routine Overloading Default Parameters. Implementating interfaces by delegation,可用以下的寫法:property MyInterface: IMyInterface read FMyInterface implements IMyInterface;新增的內定資料型態整數方面: 新增加Int64這種長度六十四位元,範圍從-2人63 to 2人63 T。 32-bit unsigned integer 新增加 Longword 型態,範圍從 0.4294967295。1除最後一項屬於Win32進階篇的內容之外,以本附錄補充說明第二、三章。 Cardinal的範圍調整成與上述Longword型態相同。浮點數方面: Real型態基於效率考量,由過去佔用48-bit調整成64-bits, 新增加Real48型態,精確度與過去的Real相同,仍是48-bit。Dynamic ArrayDelphi 4問世之前,Delphi程式設計師若需要動態長度的陣列,在不得已的情況下,往往 採用以下這種表面上陣列的語法,但實際自己配置管理記憶體的方式來處理動態陣列:#0001 procedure TForm1.Button1Click(Sender: TObject);#0002 type#0003 TIntegerArray = array0.0 of integer;#0004 PIntegerArray = ATIntegerArray;#0005 var#0006 pArrayOfInteger: PIntegerArray;#0007 j: integer;#0008 begin#0009GetMem(pArrayOfInteger, 10 * SizeOf(Integer);#0010 for j := 0 to 9 do#0011pArrayOfIntegerAj := j;#0012 FreeMem(pArrayOfInteger, 10 * SizeOf(Integer);#0013 end;如果應用Delphi 4新增加的Dynamic Array,則可改用以下的方式:var MyFlexibleArray: array of Real;定義之後,以 SetLength 函數改變陣列實際配置的記憶體大小,例如:SetLength(MyFlexibleArray, 20); / 0.19方便很多,是嗎?若想知道 Dynamic Array 實際長度,請分別以 High 與 Low 函數判斷,傳回-1時,表示是一個該陣列的長度為零,例如:#0001 procedure TForm1.Button2Click(Sender: TObject); #0002 var#0003A: array of Integer;#0004 begin#0005ShowMessage(IntToStr(High(A); / -1#0006SetLength(A, 3);#0007ShowMessage(IntToStr(High(A);/3#0008A := nil;#0009ShowMessage(IntToStr(High(A);/-1#0010 end;上述的0008這列,指定nil值將會釋放陣列所配置到的記憶體。值得注意的是,Compiler對於Dynamic Array並不會自動進行所謂的Copy-on-Write。 請看以下的程式例:#0001 procedure TForm1.Button1Click(Sender: TObject);#0002 var#0003A, B: array of Integer;#0004 begin#0005SetLength(A, 1);#0006A0 := 1;#0007B := A;#0008B0 := 2;#0009ShowMessage(IntToStr(A0); / = 2#0010 end;0008這列改的雖是B0,但Compiler顯然還沒有聰明到在可能修改陣列內容時,將陣列 內容複製一份出來(Copy on (possible) Write),於是,0009這列程式顯示的結果仍是2。於是,若要進行兩陣列各索引項目一對一的內容複製,只好自行寫迴圈一一複製,或者 採用較為簡便的寫法一一呼叫Copy函數:#0001 procedure TForm1.Button4Click(Sender: TObject);#0002 var#0003A, B: array of Integer;#0004 begin#0005SetLength(A, 1);#0006A0 := 1;#0007B := Copy(A, 0, 1);#0008B0 := 2;#0009ShowMessage(IntToStr(A0);/=1#0010ShowMessage(IntToStr(B0);/=2#0011 end;最後,請不要將Dynamic Array與第二章提到的Open Array (開放陣列)搞混了。函式參 數的開放陣列,語法雖與Dynamic Array差不多,但開放陣列指的是:不限定傳入函式的 陣列長度,Dynamic Array則是指:可變長度的陣列,兩者畢竟有所不同。以下是一則我 準備的程式範例,不難看出兩者之間的差異:#0001 type#0002 TDynamicInteger = array of integer;#0003#0004 procedure Clear_OpenArray(var A: array of Integer);#0005 var#0006 I: Integer;#0007 begin#0008 for I := 0 to High(A) do AI := 0;#0009/ SetLength(A, 20); /不可以這麼寫#0010 end;#0011#0012 / 注意, 以下兩種寫法又有不同喔#0013 / I: procedure Clear_DynamicArray(A: TDynamicInteger);#0014 / II: procedure Clear_DynamicArray(var A: TDynamicInteger);#0015 procedure Clear_DynamicArray(var A: TDynamicInteger);#0016 var#0017 I: Integer;#0018 begin#0019 for I := 0 to High(A) do AI := 0;#0020 SetLength(A, 20); /如果是 Dynamic Array, 可以這麼寫#0021 end;#0022#0023 procedure TForm1.Button3Click(Sender: TObject);#0024 var#0025 A: TDynamicInteger;#0026 begin#0027 SetLength(A, 3);#0028 Clear_OpenArray(A);#0029 ShowMessage(IntToStr(High(A); / -1#0030 Clear_DynamicArray(A);#0031/ 以下這列的結果, 要看 Cleary_DynamicArray 的#0032/參數有沒有寫 var#0033 ShowMessage(IntToStr(High(A);#0034 end;請幫我注意0004的Clear_OpenArray傳入的是由整數構成的陣列不限定陣列的長度 0015 的 Clear_DynamicArray 的寫法則是接受一個可變動陣列長度的動態陣列,若不 這樣寫,當場就變成了開放陣列了。Method and Routine Overloading所謂的Method Overloading,簡單地說:一個以上的函式使用相同的函式名稱。這項特性是Object Pascal長久以來一直有人想要卻一直沒有支援的期扮,終於,Delphi 4多了一個保留字: overload相同名稱的兩個函式,只要在宣告時額外加上overload,即使函式的參數型態不同, Delphi 也會視呼叫當時傳入的參數資料型態,決定該呼叫哪一個函式。例如以下這則例子:#0001#0002#0003#0004#0005#0006#0007#0008#0009/ 兩個 Divide 都必須寫 overload 保留字function Divide(X, Y: Double): Double; overload beginResult := X / Y; end;function Divide(X, Y: Integer): Integer; overload beginResult := X div Y;#0010end;#0011#0012procedure#0013var#0014a, b, c:#0015i, j, k:#0016begin#0017a := 10;#0018b := 3;#0019i := 10;#0020j := 3;integer;Double;TForm1.Button1Click(Sender: TObject);#0021#0022#0023#0024#0025ckShowMessage(IntToStr(c); / 3 ShowMessage(FloatToStr(k); / 3.333333. end;= Divide(a, b);= Divide(i, j);請幫我注意到0002與0007這兩列的Divide函數,函數名稱相同,但傳入的參數型態與函數的傳回值並不相同,即使如此,0023與0024呼叫到Divide時,還是會視當時參數的型態型態,決定該呼叫哪一個 Divide。很方便,是嗎?有了這項特性,我們就可以寫出應用範圍更廣彈性更大的函數一一卻不必為每一種情況各自取一個函數名稱,同時,這項特性也使得函數呼叫的方式更為一致,真 是一項早該支援的特性。除了一般的程序與函數,物件的方法也可以採用 overload 寫法, 對於物件.方法的撰寫與呼叫,肯定更能提供簡便與彈性。overload 可不可以應用在不同的兩個單元呢?答案是可以的,但是完全相同的函式宣告不 能再寫一次。例如上述程式的0007-0010,可以移到其他單元,原來的單元只要uses這個 新的單元,函數呼叫時仍然有 Overloading 的效果。可是,如果將 0007-0010 的程式碼移 到其他單元卻忘了刪除原來位置的程式,換句話說,兩個單元各有一個完全長得一樣的函 式,編譯時Delphi就搞不清楚了,結果自然是無法編譯。當然啦!同一個單元同一個範圍 發生這樣事也是不許的,各Overloading的函式,在函式宣告上多少總有些不同。Default Parameters過去,函式如果定義了六個參數,那麼,寫作函式呼叫的原始碼時,就一定得乖乖地傳入 六個參數,不許多也不許少。若是應用Default Parameters,可以只傳入五個(或者更 少)。那,那其他沒給的參數怎麼辦?沒關係,函式內部的程式將自動以預設值代 入,稍後我會說明其寫法。2舉例來說,Windows API中有一個蠻好用的函數叫MessageBox,呼叫此函數將出現一通 用對話盒,不管是顯示訊息或者徵詢使用者意見,都十分好用。像是以下這道敘述將產生 如次頁的對話盒,提醒使用者定期備份資料:Application.MessageBox(程式要結束了喔!請記得定期備份資料,訊息, MB_OK + MB_ICONINFORMATION);2TApplication 也有一個 MessageBox 方法幫我們包裝該函數的使用,省去了 WindowsHandle 參數。除了顯示資料,經由最後一個參數,彈性地搭配各位元旗標,就可以製作出不同按鈕的對話盒,詢問使用者是、否、取消等簡單的問題。應用Default Parameters的寫法,我們可以寫一個類似以下的函數:#0001 function MyMessageBox(Prompt: string;#0002 Caption: string = 訊息;#0003 Flag: LongInt = MB_OK + MB_ICONINFORMATION): integer;#0004 begin#0005 Result := Application.MessageBox(#0006 PChar(Prompt), PChar(Caption), Flag);#0007 end;#0008#0009 procedure TForm1.Button1Click(Sender: TObject);#0010 begin#0011MyMessageBox(程式要結束了喔!請記得定期備份資料);#0012 end;如此一來,我們既能有一個完整支援 MessageBox 的函數,只想顯示文字時,也能有一個精簡型式的函數可用。大家應該明顯看得出來:不必寫成兩個函數。觀察上述程式的寫法,其實也蠻容易的,只不過是在定義函數參數時,一併給定初值。不過,實際動手去寫時,還是會發現一些限制。繼續這個例子來說,參數的預設值一定得 是常數,另外,如果某一個參數開始給預設值,接在後頭的參數也必須用 Default Parameters 的寫法。為什麼得有這項限制?以上例來說,如果 0001-0003我改成:#0001 function MyMessageBox(Prompt: string;#0002Caption: string = 訊息;#0003Flag: LongInt): integer;那麼,只傳入兩個參數進去時,Delphi怎麼知道第二個參數該是Captioin或者是Caption 按預設值,第二個參數代入Flag。Visual Basic對此的解法是在呼叫函數時,一併寫明 各參數名稱與值的對應,由於這個緣故,Visual Basic甚至允許參數的次序不同也沒關係, 因為,各參數與其值的對應關係在呼叫函式時已一併註明清楚。很可惜的, Delphi 4雖有 Default Parametets,但還不支援以下的函數呼叫方式:MyMessageBox(程式要結束了喔!請記得定期備份資料,Flag =.);雖然如此,上述如果某一個參數開始給預設值,接在後頭的參數也必須用 Default Parameters 的寫法這項限制,多少還是可以搭配前一節的 Overloading 加以彌補:#0001 function MyMessageBox(Prompt: string;#0002 Caption: string = 訊息;#0003 Flag: LongInt = MB_OK + MB_ICONINFORMATION): integer; overload;#0004 begin#0005 Result := Application.MessageBox(#0006PChar(Prompt), PChar(Caption), Flag);#0007 end;#0008#0009 function MyMessageBox(Prompt: string;#0010 Flag: LongInt;#0011Caption: string = 訊息#0012): integer; overload;#0013 begin#0014 Result := Application.MessageBox(#0015PChar(Prompt), PChar(Caption), Flag);#0016 end;#0017#0018 procedure TForm1.Button1Click(Sender: TObject);#0019 begin#0020MyMessageBox(程式要結束了喔!請記得定期備份資料);#0021MyMessageBox(別說我沒告訴你喔!,MB_OK);#0022 end;(好煩的程式,一再提醒要記得備份。 :p)請幫我注意這次改寫過的程式 0009-0012,我重新調整了各參數的次序,並且分別在兩同 名函數都加上了 overload保留字,這樣,Delphi就知道該呼叫的是哪一個了。
展开阅读全文