<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 第六章 ## 過程與函數 例程(routine)是Pascal 的一個重要概念,例程由一系列語句組成,例程名是唯一的,通過例程名你可以多次調用它,這樣程序中只需要一個例程就夠了,由此避免了代碼多次重復,而且代碼也容易修改維護。從這個角度看,你可以認為例程是一種基本的代碼封裝機制。介紹完Pascal 例程的語法后,我會回過頭來舉例說明這個問題。 ### Pascal 過程與函數 Pascal中的例程有兩種形式:過程和函數。理論上說,過程是你要求計算機執行的操作,函數是能返回值的計算。兩者突出的不同點在于:函數能返回計算結果,即有一個返回值,而過程沒有。兩種類型的例程都可以帶多個給定類型的參數。 不過實際上函數和過程差別不大,因為你可以調用函數完成一系列操作,跳過其返回值(用可選的出錯代碼或類似的東西代替返回值);也可以通過過程的參數傳遞計算結果(這種參數稱為引用,下一部分會講到)。 下例定義了一個過程、兩個函數,兩個函數的語法略有不同,結果是完全相同的。 ~~~ procedure Hello; begin ShowMessage ('Hello world!'); end; function Double (Value: Integer) : Integer; begin Double := Value * 2; end; // or, as an alternative function Double2 (Value: Integer) : Integer; begin Result := Value * 2; end; ~~~ 流行的做法是用Result 給函數賦返回值,而不是用函數名,我認為這樣的代碼更易讀。 一旦定義了這些例程,你就可以多次調用,其中調用過程可執行操作;調用函數能計算返回值。如下: ~~~ procedure TForm1.Button1Click (Sender: TObject); begin Hello; end; procedure TForm1.Button2Click (Sender: TObject); var X, Y: Integer; begin X := Double (StrToInt (Edit1.Text)); Y := Double (X); ShowMessage (IntToStr (Y)); end; ~~~ > 注意:現在不必考慮上面兩個過程的語法,實際上它們是方法。只要把兩個按鈕(button)放到一個Delphi 窗體上,在設計階段單擊它們,Delphi IDE將產生合適的支持代碼,你只需要填上begin 和end 之間的那幾行代碼就行。編譯上面的代碼,需要你在窗體中加一個Edit控件。 現在回到我前面提到過的代碼封裝概念。當你調用Double 函數時,你不需要知道該函數的具體實現方法。如果以后發現了更好的雙倍數計算方法,你只需要改變函數的代碼,而調用函數的代碼不必改變(盡管代碼執行速度可能會加快!)。Hello 過程也一樣,你可以通過改變這個過程的代碼,修改程序的輸出,Button2Click 方法會自動改變顯示結果。下面是改變后的代碼: ~~~ procedure Hello; begin MessageDlg ('Hello world!', mtInformation, [mbOK]); end; ~~~ > 提示:當調用一個現有的Delphi 函數、過程或任何VCL方法時,你應該記住參數的個數及其數據類型。不過,只要鍵入函數或過程名及左括號,Delphi 編輯器中會出現即時提示條,列出函數或過程的參數表供參考。這一特性被稱為代碼參數(Code Parameters) ,是代碼識別技術的一部分。 ### 引用參數 Pascal 例程的傳遞參數可以是值參也可以是引用參數。值參傳遞是缺省的參數傳遞方式:即將值參的拷貝壓入棧中,例程使用、操縱的是棧中的拷貝值,不是原始值。 當通過引用傳遞參數時,沒有按正常方式把參數值的拷貝壓棧(避免拷貝值壓棧一般能加快程序執行速度),而是直接引用參數原始值,例程中的代碼也同樣訪問原始值,這樣就能在過程或函數中改變參數的值。引用參數用關鍵字var 標示。 參數引用技術在大多數編程語言中都有,C語言中雖沒有,但C++中引入了該技術。在C++中,用符號 &表示引用;在VB中,沒有ByVal 標示的參數都為引用。 下面是利用引用傳遞參數的例子,引用參數用var關鍵字標示: ~~~ procedure DoubleTheValue (var Value: Integer); begin Value := Value * 2; end; ~~~ 在這種情況下,參數既把一個值傳遞給過程,又把新值返回給調用過程的代碼。當你執行完以下代碼時: ~~~ var X: Integer; begin X := 10; DoubleTheValue (X); ~~~ x變量的值變成了20,因為過程通過引用訪問了X的原始存儲單元,由此改變了X的初始值。 通過引用傳遞參數對有序類型、傳統字符串類型及大型記錄類型才有意義。實際上Delphi總是通過值來傳遞對象,因為Delphi對象本身就是引用。因此通過引用傳遞對象就沒什么意義(除了極特殊的情況),因為這樣相當于傳遞一個引用到另一個引用。 Delphi 長字符串的情況略有不同,長字符串看起來象引用,但是如果你改變了該字符串的串變量,那么這個串在更新前將被拷貝下來。作為值參被傳遞的長字符串只在內存使用和操作速度方面才象引用,但是如果你改變了字符串的值,初始值將不受影響。相反,如果通過引用傳遞長字符串,那么串的初始值就可以改變。 Delphi 3增加了一種新的參數:out。out參數沒有初始值,只是用來返回一個值。out參數應只用于COM過程和函數,一般情況下最好使用更有效的var參數。除了沒有初始值這一點之外,out參數與var參數相同。 ### 常量參數 除了引用參數外,還有一種參數叫常量參數。由于不允許在例程中給常量參數賦新值,因此編譯器能優化常參的傳遞過程。編譯器會選用一種與引用參數相似的方法編譯常參(C++術語中的常量引用),但是從表面上看常參又與值參相似,因為常參初始值不受例程的影響。 事實上,如果編譯下面有點可笑的代碼,Delphi將出現錯誤: ~~~ function DoubleTheValue (const Value: Integer): Integer; begin Value := Value * 2; // compiler error Result := Value; end; ~~~ ### 開放數組參數 與C語言不同,Pascal 函數及過程的參數個數是預定的。如果參數個數預先沒有確定,則需要通過開放數組來實現參數傳遞。 一個開放數組參數就是一個固定類型開放數組的元素。 也就是說,參數類型已定義,但是數組中的元素個數是未知數。見下例: ~~~ function Sum (const A: array of Integer): Integer; var I: Integer; begin Result := 0; for I := Low(A) to High(A) do Result := Result + A[I]; end; ~~~ 上面通過High(A)獲取數組的大小,注意其中函數返回值 Result的應用, Result用來存儲臨時值。你可通過一個整數表達式組成的數組來調用該函數: `X := Sum ([10, Y, 27*I]);` 給定一個整型數組,數組大小任意,你可以直接把它傳遞給帶開放數組參數的例程,此外你也可以通過Slice 函數,只傳遞數組的一部分元素(傳遞元素個數由Slice 函數的第二個參數指定)。下面是傳遞整個數組參數的例子: ~~~ var List: array [1..10] of Integer; X, I: Integer; begin // initialize the array for I := Low (List) to High (List) do List [I] := I * 2; // call X := Sum (List); ~~~ 如果你只傳遞數組的一部分,可使用Slice 函數,如下: `X := Sum (Slice (List, 5));` 例OpenArr中可見到包括上面的完整代碼(見圖6.1)。 ![](https://box.kancloud.cn/b9a327d966181975557fc01ea555624b_348x262.png) **圖 6.1: 單擊 Partial Slice 按鈕顯示的結果** 在Delphi 4中,給定類型的開放數組與動態數組完全兼容(動態數組將在第8章中介紹)。動態數組的語法與開放數組相同,區別在于你可以用諸如array of Integer指令定義變量,而不僅僅是傳遞參數。 ### 類型變化的開放數組參數 除了類型固定的開放數組外,Delphi 還允許定義類型變化的甚至無類型的開放數組。這種特殊類型的數組元素可隨意變化,能很方便地用作傳遞參數。 技術上,array of const 類型的數組就能實現把不同類型、不同個數元素組成的數組一下子傳遞給例程。如下面Format 函數的定義(第七章中你將看到怎樣使用這個函數): ~~~ function Format (const Format: string; const Args: array of const): string; ~~~ 上面第二個參數是個開放數組,該數組元素可隨意變化。如你可以按以下方式調用這個函數: ~~~ N := 20; S := 'Total:'; Label1.Caption := Format ('Total: %d', [N]); Label2.Caption := Format ('Int: %d, Float: %f', [N, 12.4]); Label3.Caption := Format ('%s %d', [S, N * 2]); ~~~ 從上可見,傳遞的參數可以是常量值、變量值或一個表達式。聲明這類函數很簡單,但是怎樣編寫函數代碼呢?怎樣知道參數類型呢?對類型可變的開放數組,其數組元素與TVarRec 類型元素兼容。 > 注意:不要把TVarRec 記錄類型和Variant 類型使用的TVarData 記錄類型相混淆。這兩種類型用途不同,而且互不兼容。甚至可容納的數據類型也不同,因為TVarRec 支持Delphi 數據類型,而TVarData 支持OLE 數據類型。 TVarRec 記錄類型結構如下: ~~~ type TVarRec = record case Byte of vtInteger: (VInteger: Integer; VType: Byte); vtBoolean: (VBoolean: Boolean); vtChar: (VChar: Char); vtExtended: (VExtended: PExtended); vtString: (VString: PShortString); vtPointer: (VPointer: Pointer); vtPChar: (VPChar: PChar); vtObject: (VObject: TObject); vtClass: (VClass: TClass); vtWideChar: (VWideChar: WideChar); vtPWideChar: (VPWideChar: PWideChar); vtAnsiString: (VAnsiString: Pointer); vtCurrency: (VCurrency: PCurrency); vtVariant: (VVariant: PVariant); vtInterface: (VInterface: Pointer); end; ~~~ 每種記錄都有一個VType 域,乍一看不容易發現,因為它與實際意義的整型類型數據(通常是一個引用或一個指針)放在一起,只被聲明了一次。 利用上面信息我們就可以寫一個能操作不同類型數據的函數。下例的SumAll 函數,通過把字符串轉成整數、字符轉成相應的序號、True布爾值加一,計算不同類型數據的和。這段代碼以一個case語句為基礎,雖然不得不經常通過指針取值,但相當簡單,: ~~~ function SumAll (const Args: array of const): Extended; var I: Integer; begin Result := 0; for I := Low(Args) to High (Args) do case Args [I].VType of vtInteger: Result := Result + Args [I].VInteger; vtBoolean: if Args [I].VBoolean then Result := Result + 1; vtChar: Result := Result + Ord (Args [I].VChar); vtExtended: Result := Result + Args [I].VExtended^; vtString, vtAnsiString: Result := Result + StrToIntDef ((Args [I].VString^), 0); vtWideChar: Result := Result + Ord (Args [I].VWideChar); vtCurrency: Result := Result + Args [I].VCurrency^; end; // case end; ~~~ 我已在例OpenArr中加了這段代碼,該例在按下設定的按鈕后調用SumAll 函數。 ~~~ procedure TForm1.Button4Click(Sender: TObject); var X: Extended; Y: Integer; begin Y := 10; X := SumAll ([Y * Y, 'k', True, 10.34, '99999']); ShowMessage (Format ( 'SumAll ([Y*Y, ''k'', True, 10.34, ''99999'']) => %n', [X])); end; ~~~ 在圖6.2中,你可以看到調用函數的輸出和例OpenArr的窗體。 ![](https://box.kancloud.cn/7ecbf5304a3f39cacc705bef6b4f5a4c_454x268.png) **圖 6.2: 例OpenArr的窗體,當按Untype按鈕出現的信息框** ### Delphi 調用協定 32位的Delphi 中增加了新的參數傳遞方法,稱為fastcall:只要有可能,傳遞到CPU寄存器的參數能多達三個,使函數調用操作更快。這種快速調用協定(Delphi 3確省方式)可用register 關鍵字標示。 問題是這種快速調用協定與Windows不兼容,Win32 API 函數必須聲明使用stdcall 調用協定。這種協定是Win16 API使用的原始Pascal 調用協定和C語言使用的cdecl 調用協定的混合體。 除非你要調用外部Windows函數或定義Windows 回調函數,否則你沒有理由不用新增的快速調用協定。 在后面你會看到使用stdcall 協定的例子,在Delphi幫助文件的Calling conventions 主題下,你能找到有關Delphi調用協定的總結內容。 ### 什么是方法? 如果你使用過Delphi 或讀過Delphi 手冊,大概已經聽說過“方法”這個術語。方法是一種特殊的函數或過程,它與類這一數據類型相對應。在Delphi 中,每處理一個事件,都需要定義一個方法,該方法通常是個過程。不過一般“方法”是指與類相關的函數和過程。 你已經在本章和前幾章中看到了幾個方法。下面是Delphi 自動添加到窗體源代碼中的一個空方法: ~~~ procedure TForm1.Button1Click(Sender: TObject); begin {here goes your code} end; Forward 聲明 ~~~ 當使用一個標識符(任何類型)時,編譯器必須已經知道該標識符指的是什么。為此,你通常需要在例程使用之前提供一個完整的聲明。然而在某些情況下可能做不到這一點,例如過程A調用過程B,而過程B又調用過程A,那么你寫過程代碼時,不得不調用編譯器尚未看到其聲明的例程。 欲聲明一個過程或函數,而且只給出它的名字和參數,不列出其實現代碼,需要在句尾加forward 關鍵字: `procedure Hello; forward;` 在后面應該補上該過程的完整代碼,不過該過程代碼的位置不影響對它的調用。下面的例子沒什么實際意義,看過后你會對上述概念有所認識: ~~~ procedure DoubleHello; forward; procedure Hello; begin if MessageDlg ('Do you want a double message?', mtConfirmation, [mbYes, mbNo], 0) = mrYes then DoubleHello else ShowMessage ('Hello'); end; procedure DoubleHello; begin Hello; Hello; end; ~~~ 上述方法可用來寫遞歸調用:即DoubleHello 調用Hello,而Hello也可能調用DoubleHello。當然,必須設置條件終止這個遞歸,避免棧的溢出。上面的代碼可以在例DoubleH 中找到,只是稍有改動。 盡管 forward 過程聲明在Delphi中不常見,但是有一個類似的情況卻經常出現。當你在一個單元(關于單元的更多內容見下一章)的interface 部分聲明一個過程或一個函數時,它被認為是一個forward聲明,即使沒有forward關鍵字也一樣。實際上你不可能把整個例程的代碼放在interface 部分,不過你必須在同一單元中提供所聲明例程的實現。 類內部的方法聲明也同樣是forward聲明,當你給窗體或其組件添加事件時, Delphi會自動產生相應的代碼。在TForm 類中聲明的事件是forward 聲明,事件代碼放在單元的實現部分。下面摘錄的源代碼中有一個Button1Click 方法聲明: ~~~ type TForm1 = class(TForm) ListBox1: TListBox; Button1: TButton; procedure Button1Click(Sender: TObject); end; ~~~ ### 過程類型 Object Pascal 的另一個獨特功能是可定義過程類型。過程類型屬于語言的高級功能,Delphi 程序員不會經常用到它。因為后面章節要討論相關的內容(尤其是“方法指針” Delphi用得特別多),這里不妨先了解一下。如果你是初學者,可以先跳過這部分,當學到一定程度后再回過頭閱讀這部分。 Pascal 中的過程類型與C語言中的函數指針相似。過程類型的聲明只需要參數列表;如果是函數,再加個返回值。例如聲明一個過程類型,該類型帶一個通過引用傳遞的整型參數: ~~~ type IntProc = procedure (var Num: Integer); ~~~ 這個過程類型與任何參數完全相同的例程兼容(或用C語言行話來說,具有相同的函數特征)。下面是一個兼容例程: ~~~ procedure DoubleTheValue (var Value: Integer); begin Value := Value * 2; end; ~~~ > 注意:在16位Delphi中,如果要將例程用作過程類型的實際值,必須用far指令聲明該例程。 過程類型能用于兩種不同的目的:聲明過程類型的變量;或者把過程類型(也就是函數指針)作為參數傳遞給另一例程。利用上面給定的類型和過程聲明,你可以寫出下面的代碼: ~~~ var IP: IntProc; X: Integer; begin IP := DoubleTheValue; X := 5; IP (X); end; ~~~ 這段代碼與下列代碼等效: ~~~ var X: Integer; begin X := 5; DoubleTheValue (X); end; ~~~ 上面第一段代碼明顯要復雜一些,那么我們為什么要用它呢?因為在某些情況下,調用什么樣的函數需要在實際中決定,此時程序類型就很有用。這里不可能建立一個復雜的例子來說明這個問題,不過可以探究一下簡單點的例子,該例名為ProcType。該例比前面所舉的例子都復雜,更接近實際應用。 如圖6.3所示,新建一個工程,在上面放兩個radio按鈕和一個push按鈕。例中有兩個過程,一個過程使參數的值加倍,與前面的DoubleTheValue過程相似;另一個過程使參數的值變成三倍,因此命名為TripleTheValue ![](https://box.kancloud.cn/54bb6af6854fcc9095654ea637fa799a_305x179.png) **圖 6.3: 例 ProcType 窗體 ** ~~~ procedure TripleTheValue (var Value: Integer); begin Value := Value * 3; ShowMessage ('Value tripled: ' + IntToStr (Value)); end; ~~~ 兩個過程都有結果顯示,讓我們知道他們已被調用。這是一個簡單的程序調試技巧,你可以用它來檢測某一代碼段是否或何時被執行,而不用在代碼中加斷點。 當用戶按Apply 按鈕,程序會根據radio按鈕狀態選擇執行的過程。實際上,當窗體中有兩個radio按鈕時,你只能選擇一個,因此你只需要在Apply 按鈕的OnClick 事件中添加代碼檢測radio按鈕的值,就能實現程序要求。不過為了演示過程類型的使用,我舍近求遠選擇了麻煩但有趣的方法:只要用戶選中其中一個radio按鈕,按鈕對應的過程就會存入過程變量: ~~~ procedure TForm1.DoubleRadioButtonClick(Sender: TObject); begin IP := DoubleTheValue; end; ~~~ 當用戶按Apply 按鈕,程序就執行過程變量保存的過程: ~~~ procedure TForm1.ApplyButtonClick(Sender: TObject); begin IP (X); end; ~~~ 為了使三個不同的函數能訪問IP和 X變量,需要使變量在整個窗體單元中可見,因此不能聲明為局部變量(在一個方法中聲明)。一個解決辦法是,把這些變量放在窗體聲明中: ~~~ type TForm1 = class(TForm) ... private { Private declarations } IP: IntProc; X: Integer; end; ~~~ 學完下一章,你會更清楚地了解這段代碼的意思,目前只要能知道怎樣添加過程類型定義、怎樣修改相應的代碼就行了。為了用適當的值初始化上面代碼中的兩個變量,你可以調用窗體的OnCreate 事件(激活窗體后,在Object Inspector中選擇這一事件,或者雙擊窗體)。此外最好仔細看一看上例完整的源代碼。 > 在第九章的 Windows 回調函數一節,你能看到使用過程類型的實例 ### 函數重載 重載的思想很簡單:編譯器允許你用同一名字定義多個函數或過程,只要它們所帶的參數不同。實際上,編譯器是通過檢測參數來確定需要調用的例程。 下面是從VCL的數學單元(Math Unit)中摘錄的一系列函數: ~~~ function Min (A,B: Integer): Integer; overload; function Min (A,B: Int64): Int64; overload; function Min (A,B: Single): Single; overload; function Min (A,B: Double): Double; overload; function Min (A,B: Extended): Extended; overload; ~~~ 當調用方式為Min (10, 20)時,編譯器很容易就能判定你調用的是上列第一個函數,因此返回值也是個整數。 聲明重載函數有兩條原則: 每個例程聲明后面必須添加overload 關鍵字。 例程間的參數個數或(和)參數類型必須不同,返回值不能用于區分各例程。 下面是ShowMsg 過程的三個重載過程。我已把它們添加到例OverDef 中(一個說明重載和確省參數的應用程序): ~~~ procedure ShowMsg (str: string); overload; begin MessageDlg (str, mtInformation, [mbOK], 0); end; procedure ShowMsg (FormatStr: string; Params: array of const); overload; begin MessageDlg (Format (FormatStr, Params), mtInformation, [mbOK], 0); end; procedure ShowMsg (I: Integer; Str: string); overload; begin ShowMsg (IntToStr (I) + ' ' + Str); end; ~~~ 三個過程分別用三種不同的方法格式化字符串,然后在信息框中顯示字符串。下面是三個例程的調用: ~~~ ShowMsg ('Hello'); ShowMsg ('Total = %d.', [100]); ShowMsg (10, 'MBytes'); ~~~ 令我驚喜的是Delphi的代碼參數技術與重載過程及函數結合得非常好。當你在例程名后面鍵入左圓括號時,窗口中會顯示所有可用例程的參數列表,當你輸入參數時,Delphi會根據所輸入參數的類型過濾參數列表。從圖6.4你可看到,當開始輸入一個常量字符串時,Delphi只顯示第一個參數為字符串的兩個ShowMsg例程參數列表,濾掉了第一個參數為整數的例程。 ![](https://box.kancloud.cn/ac55861bef9de3fc2f3685d35683cea3_544x376.png) **圖 6.4: 窗口中代碼參數提示條顯示的重載例程參數** 重載例程必須用overload關鍵字明確標示,你不能在同一單元中重載沒有overload標示的例程,否則會出現錯誤信息: **"Previous declaration of '<name>' was not marked with the 'overload' directive."**。不過你可以重載在其他單元中聲明的例程,這是為了與以前的Delphi版本兼容,以前的Delphi版本允許不同的單元重用相同的例程名。無論如何,這是例程重載的特殊情況不是其特殊功能,而且不小心會出現問題。 例如在一個單元中添加以下代碼: ~~~ procedure MessageDlg (str: string); overload; begin Dialogs.MessageDlg (str, mtInformation, [mbOK], 0); end; ~~~ 這段代碼并沒有真正重載原始的MessageDlg 例程,實際上如果鍵入: `MessageDlg ('Hello');` 你將得到一個有意思的錯誤消息,告訴你缺少參數。調用本地例程而不是VCL的唯一途徑是明確標示例程所在單元,這有悖于例程重載的思想: `OverDefF.MessageDlg ('Hello');` ### 確省參數 Delphi 4 中添加了一個新功能,即允許你給函數的參數設定確省值,這樣調用函數時該參數可以加上,也可以省略。下例把應用程序全程對象的MessageBox 方法重新包裝了一下,用PChar 替代字符串,并設定兩個確省值: ~~~ procedure MessBox (Msg: string; Caption: string = 'Warning'; Flags: LongInt = mb_OK or mb_IconHand); begin Application.MessageBox (PChar (Msg), PChar (Caption), Flags); end; ~~~ 使用這一定義,你就可以用下面任一種方式調用過程: ~~~ MessBox ('Something wrong here!'); MessBox ('Something wrong here!', 'Attention'); MessBox ('Hello', 'Message', mb_OK); ~~~ 從圖6.5中可以看到,Delphi的代碼參數提示條會用不同的風格顯示確省值參數,這樣你就很容易確定哪個參數是可以省略的。 ![](https://box.kancloud.cn/669b504254939b026de6231234098252_650x376.png) **圖 6.5: Delphi代碼參數提示條用方括號標示確省值參數,調用時可以省略該參數** > 注意一點,Delphi 不產生任何支持確省參數的特殊代碼,也不創建例程的多份拷貝,缺省參數是由編譯器在編譯時添加到調用例程的代碼中。 使用確省參數有一重要限定:你不能“跳過”參數,如省略第二個參數后,不能把第三個參數傳給函數: `MessBox ('Hello', mb_OK); // error ` 確省參數使用主要規則:調用時你只能從最后一個參數開始進行省略,換句話說,如果你要省略一個參數,你必須省略它后面所有的參數。 確省參數的使用規則還包括: 帶確省值的參數必須放在參數表的最后面。 確省值必須是常量。顯然,這限制了確省參數的數據類型,例如動態數組和界面類型的確省參數值只能是 nil;至于記錄類型,則根本不能用作確省參數。 確省參數必須通過值參或常參傳遞。引用參數 var不能有缺省值。 如果同時使用確省參數和重載可能會出現問題,因為這兩種功能可能發生沖突。例如把以前ShowMsg 過程改成: ~~~ procedure ShowMsg (Str: string; I: Integer = 0); overload; begin MessageDlg (Str + ': ' + IntToStr (I), mtInformation, [mbOK], 0); end; ~~~ 編譯時編譯器不會提出警告,因為這是合法的定義。 然而編譯調用語句: `ShowMsg ('Hello');` 編譯器會顯示 Ambiguous overloaded call to 'ShowMsg'.( 不明確重載調用ShowMsg)。注意,這條錯誤信息指向新定義的重載例程代碼行之前。實際上,用一個字符串參數無法調用ShowMsg 過程,因為編譯器搞不清楚你是要調用只帶字符串參數的ShowMsg 過程,還是帶字符串及整型確省參數的過程。遇到這種問題時,編譯器不得不停下來,要求你明確自己的意圖。 * * * * * ### 結束語 過程和函數是編程的一大關鍵,Delphi 中的方法就是與類及對象關聯的過程和函數。 下面幾章將從字符串開始詳細講解Pascal的一些編程元素。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看