私の特定のクラスでは、オブジェクトの独立したコピーを返す関数TPersistent
を提供したいと思います。Clone
Clone
すべての子孫に関数を実装せずに、子孫でこれを正しく機能させることは可能ですか?
これは、不明なフィールドのクローン作成やディープ クローン作成 (RTTI を使用して行うことができます) に関するものではありません。以下の最小限の例では、関数を配置したい場所を確認できますClone
。
データのコピーに使用Assign()
するため、どの子孫でも機能します。問題はコンストラクタです。コメントを参照してください。その子孫の正しいコンストラクターを呼び出すにはどうすればよいですか? それが非常に難しい場合は、 をオーバーライドせずにコンストラクタをオーバーライドする子孫はないと想定しても問題ありませClone
ん。
program Test;
uses System.SysUtils, System.Classes;
type
TMyClassBase = class abstract(TPersistent)
public
constructor Create; virtual; abstract;
function Clone: TMyClassBase; virtual; abstract;
end;
TMyClassBase<T> = class abstract(TMyClassBase)
private
FValue: T;
public
constructor Create; overload; override;
function Clone: TMyClassBase; override;
procedure Assign(Source: TPersistent); override;
property Value: T read FValue write FValue;
end;
TMyClassInt = class(TMyClassBase<Integer>)
public
function ToString: string; override;
end;
TMyClassStr = class(TMyClassBase<string>)
public
function ToString: string; override;
end;
constructor TMyClassBase<T>.Create;
begin
Writeln('some necessary initialization');
end;
procedure TMyClassBase<T>.Assign(Source: TPersistent);
begin
if Source is TMyClassBase<T> then FValue:= (Source as TMyClassBase<T>).FValue
else inherited;
end;
function TMyClassBase<T>.Clone: TMyClassBase;
begin
{the following works, but it calls TObject.Create!}
Result:= ClassType.Create as TMyClassBase<T>;
Result.Assign(Self);
end;
function TMyClassInt.ToString: string;
begin
Result:= FValue.ToString;
end;
function TMyClassStr.ToString: string;
begin
Result:= FValue;
end;
var
ObjInt: TMyClassInt;
ObjBase: TMyClassBase;
begin
ObjInt:= TMyClassInt.Create;
ObjInt.Value:= 42;
ObjBase:= ObjInt.Clone;
Writeln(ObjBase.ToString);
Readln;
ObjInt.Free;
ObjBase.Free;
end.
出力は
some necessary initialization
42
したがって、正しいクラスが出てきました。この最小限の例では正しく動作しますが、残念ながら、必要な初期化は行われませんでした (2 回表示されるはずです)。
私はそれを明確にし、あなたが私のサンプルコードを気に入ってくれることを願っています:) -他のコメントや改善点も感謝します. 私のAssign()
実装は大丈夫ですか?