使用构造函数或实例函数复制对象实例的优缺点是什么?
示例A:
type
TMyObject = class
strict private
FField: integer;
public
constructor Create(srcObj: TMyObject); overload;
//alternatively:
//constructor CreateFrom(srcObj: TMyObject);
property Field: integer read FField;
end;
constructor TMyObject.Create(srcObj: TMyObject);
begin
inherited Create;
FField := srcObj.Field;
end;
例B:
type
TMyObject = class
strict private
FField: integer;
public
function Clone: TMyObject;
property Field: integer read FField;
end;
function TMyObject.Clone: TMyObject;
begin
Result := TMyObject.Create;
Result.FField := FField;
end;
立即想到一个主要区别 - 在后一种情况下,Create构造函数必须是虚拟的,以便可以基于TMyObject构建支持Clone的类层次结构。
假设这不是问题 - TMyObject和基于它的所有东西完全在我的控制之下。在Delphi中进行复制构造函数的首选方法是什么?您觉得哪个版本更具可读性?你什么时候使用前者或后者?讨论。 :)
编辑: 我对第一个例子的主要关注是,与第二种方法相比,使用非常繁重,即
newObj := TMyObject.Create(oldObj)
VS。
newObj := oldObj.Clone;
EDIT2或“我为什么要单线操作”
我同意在大多数情况下,Assign是一种合理的方法。通过简单地使用assign来实现“复制构造函数”是合理的。
我通常在多线程并通过消息队列传递对象时创建此类副本。如果对象创建速度很快,我通常会传递原始对象的副本,因为这样可以简化对象所有权问题。
IOW,我更喜欢写
Send(TMyObject.Create(obj));
或
Send(obj.Clone);
到
newObj := TMyObject.Create;
newObj.Assign(obj);
Send(newObj);
答案 0 :(得分:27)
第一个添加有关要创建哪个对象的信息,第二个不添加。这可用于实例化例如班级的后裔或祖先
Delphi方式(TPersistent
)分离创建和克隆:
dest := TSomeClass.Create;
dest.Assign(source);
并具有相同的属性,您明确选择要实例化的类。但是你不需要两个构造函数,一个用于正常使用,另一个用于你想要克隆的构造函数。
因在线要求而修改 您可以使用Delphi元类(未经测试)
混合它type
TBaseSomeObject = class;
TBaseObjectClass = class of TBaseSomeObject;
TBaseSomeObject = class(TPersistent)
function Clone(t: TBaseObjectClass = nil): TBaseSomeObject; virtual;
end;
...
function TBaseSomeObject.Clone(t: TBaseObjectClass = nil): TBaseSomeObject;
begin
if Assigned(t) then
Result := t.Create
else
Result := TBaseObjectClass(Self.ClassType).Create;
Result.Assign(Self);
end;
SendObject(obj.Clone); // full clone.
SendObject(obj.Clone(TDescandantObject)); // Cloned into Descendant object
其他方面,只需实施assign()
运营商,您就可以采用多种方式。
<强> EDIT2 强>
我用D2009中测试的代码替换了上面的代码。这些类型的某些依赖关系可能会让您感到困惑,希望通过这种方式更加清晰。当然,你必须研究分配机制。我还测试了metaclass=nil
默认参数并且它有效,所以我添加了它。
答案 1 :(得分:6)
我认为没有一种正确的方式只取决于个人风格。 (正如马可指出的那样,还有更多方法。)
如果您使用流实施分配,则只有一个地方可以担心需要哪些字段可用。
答案 2 :(得分:3)
我喜欢 clone 样式 - 但仅限于Java(或任何其他GC语言)。我在Delphi中使用过一段时间,但大多数情况下我仍然使用Create
和Assign
,因为更明确的是谁负责破坏对象。