自アプリ用にパネルのクラスを作っています。
コンパイル時に
≪[警告] TestMain.pas(66): 'Create' メソッドが基本型 'TCustomPanel' の仮想メソッドを隠しました≫
というような警告がでます。以下がコードの一部です。
overload の部分を override に変更すると
≪[エラー] TestMain.pas(63): 'Create' の宣言がすでに定義されているものと異なります≫
となってしまいます。
どのように対処すればよいのでしょうか?
TMyPanel = class (TCustomPanel)
private
〜<略>〜
public
〜<略>〜
constructor Create(AOwner: TComponent; PMain: TPanel); overload;
end;
調べてみると見つかりました。
reintroduce;
警告を無視するんですね。
お騒がせしました。
補足
>reintroduce;
は、上位クラスから呼ばれなくなりますので注意してください。
上位クラスは、上位クラスの段階で実装されたメソッドを呼び出します。
interface
type
TClassA = class
private
FTestValue: integer;
protected
function GetValue: integer; virtual;
procedure SetValue(const Value: integer); virtual;
public
constructor Create;
property TestValue: integer read GetValue write SetValue;
end;
TClassB = class( TClassA)
protected
procedure SetValue(const Value: integer); override;
end;
TClassC = class( TClassA)
protected
procedure SetValue(const Value: integer); reintroduce;
end;
TForm1省略
implementation
{ TClassA }
constructor TClassA.Create;
begin
SetValue( 1);
end;
function TClassA.GetValue: integer;
begin
Result:= FTestValue;
end;
procedure TClassA.SetValue(const Value: integer);
begin
FTestValue:= Value;
end;
{ TClassB }
procedure TClassB.SetValue(const Value: integer);
begin
inherited SetValue( Value+1);
//1足しますが overrideされています。
end;
{ TClassC }
procedure TClassC.SetValue(const Value: integer);
begin
inherited SetValue( Value+1);
//1足しますが、reintroduceされています。
end;
//テスト
procedure TForm1.Button1Click(Sender: TObject);
begin
with TClassA.Create do
try
Memo1.Lines.Add( 'CLASS-A '+IntTOStr(TestValue));
finally
Free;
end;
with TClassB.Create do
try
Memo1.Lines.Add( 'CLASS-A OVERRIDE '+IntTOStr(TestValue));
finally
Free;
end;
with TClassC.Create do
try
Memo1.Lines.Add( 'CLASS-A REINTRODUCE '+IntTOStr(TestValue));
finally
Free;
end;
end;
結果、
CLASS-A 1
CLASS-A OVERRIDE 2
CLASS-A REINTRODUCE 1
となり、
CLASS-A REINTRODUCEは、上位クラスからは呼ばれていないのが確認できます。
したがって reintroduceができるのは、
・上位クラスがそのメソッドを内部から呼んでいない
・上位クラスがそのメソッドを内部から呼んでいても問題ない
場合に限られます。
ちなみに、TCustomPanelの Create は reintroduceを使っても、問題ありません。
しかし、
type
ClassAClasses = class of TClassA;
などとして
TClassC = class( TClassA)
protected
constructor Create; reintroduce; //追加
procedure SetValue(const Value: integer); reintroduce;
end;
のように変更。
implementation
constructor TClassC.Create;
begin
inherited;
SetValue( 100);
end;
//テスト
procedure TForm1.Button2Click(Sender: TObject);
function CreateClass( SomeClass: ClassAClasses):TClassA;
begin
Result:= SomeClass.Create;
end;
begin
with CreateClass(TClassA) do
try
Memo1.Lines.Add( 'CLASS-A '+IntTOStr(TestValue));
finally
Free;
end;
with CreateClass(TClassB) do
try
Memo1.Lines.Add( 'CLASS-A OVERRIDE '+IntTOStr(TestValue));
finally
Free;
end;
with CreateClass(TClassC) do
try
Memo1.Lines.Add( 'CLASS-A REINTRODUCE '+IntTOStr(TestValue));
finally
Free;
end;
end;
結果、
CLASS-A 1
CLASS-A OVERRIDE 2
CLASS-A REINTRODUCE 1
となり、TClassCのコンストラクタが呼ばれません。
Class of hoehoe 等を使って動的にクラスを生成したりする場合には、
reintroduceのコンストラクタが 呼び出されないということを
覚えておく必要があると思います。
機転を利かせ、動的にクラスが変化する機構を実装した場合などには
バグになるので注意が必要です(はまります)
ツイート | ![]() |