同じユニット内に次のような2つの helper があった場合
type TIntegerHelperA = record helper for Integer function foo: String; end; TIntegerHelperB = record helper for Integer function bar: String; end; function TIntegerHelperA.foo: String; begin Result := 'A'; end; function TIntegerHelperB.bar: String; begin Result := 'B'; end; begin Writeln(1000000.foo); // コンパイルエラー Writeln(1000000.bar); // OK end.
直近の helper が有効になります。
メソッド名が違っても関係ありません。
それは helper が別のユニットにあったとしてもです。
unit Unit1; interface type TIntegerHelperA = record helper for Integer function foo: String; end; (略)
unit Unit2; interface type TIntegerHelperB = record helper for Integer function bar: String; end; (略)
uses するとき Unit2 を後にすると、TIntegerHelperA がエラーに。
uses Unit1, Unit2; begin Writeln(1000000.foo); // コンパイルエラー Writeln(1000000.bar); // OK end.
Unit1 を後にすると、TIntegerHelperB がエラーになります。
uses Unit2, Unit1; begin Writeln(1000000.foo); // OK Writeln(1000000.bar); // コンパイルエラー end.
同じメソッド名を持つ helper が定義してあると、直近の helper メソッドが呼ばれます。
意図していないメソッドが呼ばれる事が無いよう注意が必要です。
意図していないメソッドが呼ばれる事が無いよう注意が必要です。
では、次のような場合はどうなるでしょう?
type TTest = class(TObject); TObjectHelper = class helper for TObject function Hello: String; end; TTestHelper = class helper for TTest function Hello: String; end; { TObjectHelper } function TObjectHelper.Hello: String; begin Result := 'Hello, TObjectHelper'; end; { TTestHelper } function TTestHelper.Hello: String; begin Result := 'Hello, TTestHelper'; end; var Test: TTest; begin Test := TTest.Create; try Writeln(Test.Hello); finally Test.Free; end; end.
この場合、コンパイルエラーにはなりません。
helper は、1つの class / record につき1つ有効なので、継承元と継承先のクラスは別個に helper を持てるからです。
上の場合、出力される値は
Hello, TTestHelper
となります。
では、さらに下記の様にキャストした場合は、どうなるでしょう?
var
Test: TTest;
begin
Test := TTest.Create;
try
Writeln(TObject(Test).Hello); // TObject にキャスト
finally
Test.Free;
end;
end.
結果は
Hello, TObjectHelper
と出力されます。 これらの事から helper はコンパイル時に決定される機構であることが判ります。
ヘルプにも
ヘルパは、識別子を解決するときに、コンパイラが使用するスコープの範囲を広げる機能です (from DocWiki)と書いてありますしね。
0 件のコメント:
コメントを投稿