在我的特定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
所以,正确的类出来了,它在这个最小的例子中正常工作,但不幸的是,我的必要的初始化没有完成(应该出现两次)。
我希望我能说清楚,你喜欢我的示例代码:) - 我也非常感谢任何其他意见或改进。 我的Assign()
实施是否正常?
答案 0 :(得分:2)
您不需要创建非泛型基类构造函数abstract。您可以在那里实现克隆,因为您有一个虚拟构造函数。
此外,您不需要将Clone
方法设为虚拟。
type
TMyClassBase = class abstract(TPersistent)
public
constructor Create; virtual; abstract;
function Clone: TMyClassBase;
end;
...
type
TMyClassBaseClass = class of TMyClassBase;
function TMyClassBase.Clone: TMyClassBase;
begin
Result := TMyClassBaseClass(ClassType).Create;
try
Result.Assign(Self);
except
Result.DisposeOf;
raise;
end;
end;
请注意,ClassType
会返回TClass
。我们将其转换为TMyClassBaseClass
以确保我们调用您的基类虚构造函数。
我也不明白为什么你从中提出了TMyClassBase<T>
抽象和衍生的规范。您应该能够在泛型类中实现所需的一切。
答案 1 :(得分:-2)
这似乎是这样做的:
function TMyClassBase<T>.Clone: TMyClassBase;
begin
{create new instance using empty TObject constructor}
Result:= ClassType.Create as TMyClassBase<T>;
{execute correct virtual constructor of descendant on instance}
Result.Create;
{copy data to instance}
Result.Assign(Self);
end;
但是,我以前从未见过 - 感觉非常非常错误......
我验证它正确初始化了目标对象的数据,并且实际上只调用了后代构造函数 。我看没有问题,也没有内存泄漏报告。使用Delphi 10.2.2进行测试。请评论:)