基本クラスと派生クラスの 2 つのクラスがあります。基本クラスは、パラメーターを持つ仮想メソッドを定義します。
function ToName(MsgIfNil:string=''); virtual;
派生クラスはメソッドを再定義します。
function ToName(MsgIfNil:string=''); reintroduce;
両方のメソッドの実装は、次のコードに似ています。
function TBaseClass.ToName(MsgIfNil:string)
begin
if (Self=nil) then
Result := MsgIfNil
else
Result := Self.SomeProperty;
end;
問題は次のとおりです。
1) 派生クラスにメソッドを再導入せず、通常のオーバーライド キーワードを使用すると、このメソッドを呼び出すとアクセス違反が発生する
2) nil であるオブジェクトからメソッドを呼び出し、オブジェクトの推定クラスが TBaseObject である場合、ベース仮想メソッドを呼び出す代わりにクラッシュ (AV) します。
メソッドでパラメーターが定義されていない場合は、AV なしで正しいメソッドが呼び出されます。派生クラスのメソッドがオーバーライドされていても問題なく動作します。
上記のソリューションは、TBaseClass から派生した任意のクラスのオブジェクトでうまく機能することに注意してください。
Self=nil で呼び出すことができ、仮想化してパラメーターを使用できる仮想メソッドを定義するにはどうすればよいですか?
私は確かに、内部仮想メソッド呼び出しの配管についての理解を深める必要があります...
注: 私の使用例では、nil オブジェクトの呼び出しは正当です。例外を非表示にするのではなく、リンクされていないオブジェクトを報告するために使用されます。例: myEdit.Text := APerson.Manager.ToName('マネージャーが定義されていません');
適切な解決策についてのアドバイスをありがとう
upd5 で Delphi 2010 を使用する
編集: AV をトリガーするコードのより完全な例を追加する
TBaseClass = class(TObject)
private
FMyName: string;
public
property MyName: string read FMyName;
function ToName(MsgIfNil:string=''):string; virtual;
end;
TDerivedClass = class(TBaseClass)
private
FSpecialName: string;
public
property SpecialName:string read FSpecialName;
function ToName(MsgIfNil:string=''):string; reintroduce;
end;
TBaseClass.ToName(MsgIfNil:string):string;
begin
if (Self=nil) then
Result := MsgIfNil
else
Result := MyName;
end;
TDerivedClass.ToName(MsgIfNil:string):string;
begin
if (Self=nil) then
Result := MsgIfNil
else
Result := SpecialName;
end;
// Now a sample program
var
aPerson: TBaseClass;
aSpecialist: TDerivedClass;
begin
aPerson := TBaseClass.Create;
aPerson.MyName := 'a person';
aSpecialist := TDerivedClass.Create;
aSpecialist.SpecialName := 'a specialist';
aSpecialist := nil; // For example sake, never do this in my use case :)
// This works here,
// but triggers an AV if ToName is marked as override instead of reintroduce
ShowMessage('Name of the specialist: '+aSpecialist.ToName('No specialist!'));
aPerson := nil;
// This triggers an AV, TBaseClass.ToName is never called
ShowMessage('Name of the person: '+aPerson.ToName('No person!'));
end;
上記のコードはコンパイルできない可能性があります。これは、より完全な例を示すことのみを目的としています。
テイクウェイ
VMT はオブジェクト参照にリンクされており、オブジェクト クラスに関係なく、nil オブジェクトで仮想メソッドを呼び出すことはできないことがわかりました (オブジェクトは宣言された型を調べて、ToName メソッドの一致するアドレスを取得することさえしません)。 )
私は hvd のソリューションを受け入れました。これは、vs nil をチェックする必要があるメソッド (追加する基本メソッドは 1 つだけ) に非常に効果的であるためです。
すべての回答に感謝します。