Delphiでのプロシージャと関数の使用

遅かれ早かれ、どのプログラマーもプロシージャーと関数を使用する必要があります。 Pascalでは、複雑なものは何もないことを覚えていますが、通常は書籍に記載されていないものもありますが、プログラムを正しくコンパイルするためには知っておく必要があります。



ブラケット



パラメータなしでプロシージャや関数を呼び出すときに角かっこを追加することは、Delphiでは長らく目新しいことではありませんでしたが、この機能はほとんど知られていません。 この機会は、2つの言語(C ++およびDelphi)で作業する必要のあるプログラマーに感謝されます。異なる言語でプロシージャと関数を呼び出すときに構文の違いを常に覚えておく必要がないためです。 Delphiでは、以下の両方のオプションが有効と見なされます。



Form1.Show;

Form1.Show();








過負荷機能



初めて、プロシージャと関数のオーバーロードの概念がDelphi 4で実装されました。これにより、同じ名前で異なるパラメータのリストを持つ複数の異なるプロシージャと関数を使用できます。 このようなプロシージャと関数は、オーバーロードディレクティブを使用して説明する必要があります。



procedure Test (I: integer); overload;

procedure Test (S: string); overload;

procedure Test (D: double); overload;








テストプロシージャを呼び出すと、Delphi自体は、渡されたパラメータに応じて、3つのプロシージャのいずれを実行する必要があるかを決定します。 ただし、これは最も安全な言語機能ではないことに注意してください。 オーバーロードされたプロシージャと関数を使用すると、プログラム内の微妙なバグの尽きることのないソースになります。 したがって、この機会を慎重に使用してください。



パラメータを渡す



Pascalを使用すると、値または参照によってパラメーターを関数やプロシージャに渡すことができます。 渡されるパラメーターは、組み込み型またはユーザー定義型のいずれか、またはオープン配列にすることができます。 プロシージャまたは関数の値が変更されない場合、パラメータは定数にすることもできます。



値でパラメーターを渡す


このパラメーター転送モードはデフォルトで使用されます。 パラメータが値で渡される場合、この変数のローカルコピーが作成され、プロシージャまたは関数への処理のために提供されます。 次の例を見てください。



procedure Test(s: string);







このプロシージャが呼び出されると、パラメータとして渡された文字列のコピーが作成され、テストプロシージャが機能します。 さらに、文字列に加えられたすべての変更は、元の変数には影響しません。



ただし、これはオブジェクトには適用されません。 たとえば、変数(またはオブジェクトのインスタンス)TStringListが関数に渡される場合、この場合、転送は参照によって行われます(明示的に示されていなくても)。 この送信方法は大多数の中で最も好まれていますが、同時に最も実用的でもありません。 メソッドを実行するには、追加のメモリを割り当てて、転送された変数の正確なコピーを作成します。 この問題を解決するには、以下で説明する方法のいずれかを使用します。



参照によるパラメーターの受け渡し


Pascalでは、参照によって関数またはプロシージャにパラメーターを渡すこともできます。このようなパラメーターはパラメーター変数と呼ばれます。 パラメータを参照渡しすると、関数またはプロシージャが受信したパラメータ値を変更できるようになります。 参照渡しでパラメーターを渡すには、varキーワードを使用します。これは、呼び出されたプロシージャまたは関数のパラメーターリストに配置されます。



procedure ChangeMe(var x: longint);

begin

x := 2; //

end;








変数xのコピーを作成する代わりに、varキーワードは変数x自体のアドレスを渡す必要があります。これにより、プロシージャは値を直接変更できます。



定数を渡す


関数またはプロシージャに転送されるデータを変更する必要がない場合は、パラメータを定数として記述することができます。 constキーワードは、パラメーターが変更されないようにするだけでなく、コンパイラーがストリングとレコードを渡すためのより最適なコードを生成できるようにします。 定数パラメーターの宣言の例を次に示します。



procedure Test(const s: string );







オープン配列を渡す


パラメータのオープン配列により、異なる数のパラメータを関数またはプロシージャに渡すことができます。 同じタイプの要素のオープン配列またはさまざまなタイプの定数の配列のいずれかをパラメーターとして渡すことができます。 次の例では、整数のオープン配列をパラメーターとして渡す関数を宣言しています。



function AddEmUp(A: array of integer): integer;







オープン配列では、定数から変数、定数、または式を渡すことができます。



関数またはプロシージャで実際に送信されたパラメータの配列に関する情報を取得するには、High、Low、およびSizeOf関数を使用できます。



Object Pascalはconstの配列タイプもサポートしているため、1つの配列でさまざまなタイプのデータを転送できます。 このような配列を使用してパラメータを取得する関数またはプロシージャを宣言するための構文は次のとおりです。



procedure WhatHaveIGot( A: array of const );







たとえば、次の演算子を使用して、上記で宣言した関数を呼び出すことができます。



procedure WhatHaveIGot( ['Text', 10, 5.5, @WhatHaveIGot, 3.14, true, 'c'] );







定数の配列に関数またはプロシージャを渡すとき、コンパイラは暗黙的に渡されたすべてのパラメータをTVarRec型に変換します。 TVarRecデータ型は、次のようにSystemモジュールで宣言されます。



PVarRec = ^TVarRec;

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);

vtWideString: (VWideString: Pointer);

vtInt64: (VInt64: PInt64);

end;








VTypeフィールドは、TVarRecレコードのこのインスタンスに含まれるデータのタイプを決定し、指定された値のいずれかを取ることができます。



定数の配列はさまざまなタイプのデータを送信できるため、受信したパラメーターを処理する関数またはプロシージャを作成するときに、特定の問題が発生する可能性があります。 このような配列を使用する例として、WhatHaveIGotプロシージャの実装を検討してください。このプロシージャは、結果のパラメータ配列の要素をスキャンし、そのタイプを表示します。



procedure WhatHaveIGot( A: array of const );

var

i: integer;

TypeStr: string;

begin

for i := Low(A) to High(A) do

begin

case A[i].VType of

vtInteger : TypeStr := 'Integer';

vtBoolean : TypeStr := 'Boolean';

vtChar : TypeStr := 'Char';

vtExtended : TypeStr := 'Extended';

vtString : TypeStr := 'String';

vtPointer : TypeStr := 'Pointer';

vtPChar : TypeStr := 'PChar';

vtObject : TypeStr := 'Object';

vtClass : TypeStr := 'Class';

vtWideChar : TypeStr := 'WideChar';

vtPWideChar : TypeStr := 'PWideChar';

vtAnsiString : TypeStr := 'AnsiString';

vtCurrency : TypeStr := 'Currency';

vtVariant : TypeStr := 'Variant';

vtInterface : TypeStr := 'Interface';

vtWideString : TypeStr := 'WideString';

vtInt64 : TypeStr := 'Int64';

end;

ShowMessage( Format( 'Array item %d is a %s', [i, TypeStr] ) );

end;

end;








デフォルトのパラメーター値



Delphiには非常に便利な機能が1つあります-デフォルトのパラメーター値の使用です。 プロシージャまたは関数パラメータのデフォルト値を設定できます。 この値は、このパラメーターの値を指定せずにプロシージャまたは関数が呼び出されたときに使用されます。 プロシージャーまたは関数の宣言では、パラメーターのデフォルト値は、名前に続く等号の後に示されます。 これを次の例で説明しましょう。



procedure HasDefVal( s: string; i: integer = 0 );







このような宣言は、HasDefValプロシージャを2つの方法で呼び出すことができることを意味します。 最初の場合-通常どおり、両方のパラメーターを示します:



procedure HasDefVal( 'Hello', 26 );







2番目の場合、パラメーターsの値のみを設定でき、パラメーターiにはデフォルトで設定された値を使用します。



procedure HasDefVal( 'Hello' );







デフォルト設定を使用する場合、留意すべきいくつかのルールがあります。



デフォルトのパラメータ値を使用することの重要な利点の1つは、既存のプロシージャと関数の機能を後方互換性で簡単に拡張できることです。 プログラムがソフトウェア市場にリリースされ、その主要なリンクが2つの整数を追加する機能であるとします。



function Add( I1, I2: integer ): integer;

begin

Result := I1 + I2;

end;








また、3つの数値を追加する機能をプログラムに追加することの妥当性が研究によって示されているとします。 ただし、既存の関数を3つの数字を追加する関数に置き換えると、関数に別のパラメーターを追加するためにコンパイルが停止する多くのテキストをリダイレクトする必要があります。 ただし、デフォルトのパラメーター値を使用すると、問題は簡単かつ簡単に解決されます。 以下に示すように、関数宣言を変更するだけで十分です。



function Add( I1, I2: integer; I3: integer = 0 ): integer;

begin

Result := I1 + I2 + I3;

end;








ディレクティブ{$ X-}



{$ X-}ディレクティブは、プロシージャとして関数を呼び出すことを禁止します(戻り結果を無視します)。 デフォルトでは、このモードは有効になっています({$ X +})。 したがって、[プロジェクトオプション]ダイアログボックスの[コンパイラ]タブにある[拡張構文]オプションがオフの場合、またはコンパイラディレクティブ{$ X-}が指定されている場合、Result変数の使用は許可されません。



各Objecl Pascal言語関数には、戻り値に対応するように設計されたResultというローカル変数があります。 また、特定の関数と同じ名前の変数に値を割り当てることにより、関数から値を返すこともできます。 これは、以前のバージョンから保持されているPascal言語の標準構文です。 関数の本体で名前を持つ変数を使用する場合、この名前の処理に大きな違いがあることを忘れないでください-それはすべて、代入演算子の左側または関数テキストの他の場所で、それがどこにあるかに依存します。 関数名が代入演算子の左側に示されている場合、関数によって返される値が割り当てられていると見なされます。 他のすべての場合では、この関数の再帰呼び出しが実行されると想定されます。



手順と機能は、プログラミング言語の重要な概念であり、それなしでは深刻なプログラムは実行できません。 したがって、彼らの仕事のメカニズムを完全に理解することは非常に重要です。



All Articles