使用虚构造函数重置为初始状态

时间:2010-12-07 14:34:52

标签: delphi constructor virtual

我对Delphi中提供的虚拟构造函数没有任何经验。我考虑在类层次结构中使用虚拟ctors来将实例重置为初始状态,如下所示:

A = class
end;
B = class(A)
end;
C = class(B)
end;

FooA = class
    a_ : A;
    constructor Create(inst : A); overload;
    constructor Create; overload; virtual; abstract;
    destructor Destroy; override;
    function Bar : A;
end;

FooB = class(FooA)
    b_ : B;
    constructor Create; override;
    constructor Create(inst : B); overload;
end;

FooC = class(FooB)
// ...
end;

{ FooA }
constructor FooA.Create(inst: A);
begin
    inherited Create;
    a_ := inst;
end;

destructor FooA.Destroy;
begin
    FreeAndNil(a_);
    inherited;
end;

function FooA.Bar : A;
begin
    Result := a_;
    a_ := nil;

    // here comes the magic
    Self.Create;
end;

{ FooB }
constructor FooB.Create;
begin
    b_ := B.Create;
    inherited Create(b_);
end;

constructor FooB.Create(inst: B);
begin
    inherited Create(inst);
    b_ := inst;
end;
{ FooC } // ...

var
    fc : FooA;
    baz : A;
begin
    fc := FooC.Create;
    baz := fc.Bar;
    WriteLn(baz.ClassName);
    FreeAndNil(baz);
    FreeAndNil(fc);
    ReadLn;
end.

此设计中是否存在任何问题/陷阱?这个简单的例子就像一个魅力,但我觉得有点不安的调用构造函数(不构造任何东西)就像这样。

编辑:

我决定将初始化移动到受保护区域中具有有意义名称的方法,这让我感觉更好; - )

FooA = class
strict private
    a_ : A;
strict protected
    procedure SetInst; overload; virtual; abstract;
    procedure SetInst(i : A); overload;
public
    constructor Create;
    destructor Destroy; override;
    function Foo : A;
end;

2 个答案:

答案 0 :(得分:3)

编写很少的类来支持使用构造函数作为重新初始化程序。他们通常假设任何动态分配的内存已经分配了 not 。如果你控制了你正在使用的所有类,那么请继续并小心地使用构造函数作为重新初始化器。

即使你处于控制之中,我仍然会反对它。 这不是惯用的Delphi ;阅读你的代码的任何人(甚至你,从现在开始的几个星期或几个月)都会被你的非标准使用构造函数混淆 - 至少在开始时。这不值得麻烦。如果调用Bar函数应该释放A对象的所有权并创建一个新实例,那么编写具有明确名称的函数。

答案 1 :(得分:1)

Rob认为这是一个非常奇怪的代码,可能会让人感到困惑,并且将代码转移到初始化例程是一个好主意。如果您想知道,虚拟构造函数的主要目的是完全不同的东西:更容易支持“工厂”样式对象创建。

某些外部源提供了一些可以识别基类后代的数据,并且工厂使用类引用并调用基类中定义的虚拟构造函数。这样你最终得到了一个后代类的实例,而不必将后代类的知识硬编码到工厂代码中。

如果这听起来有点奇怪,请查看DFM文件。它有一个从TComponent下载的表单对象列表及其发布的属性。当表单读取代码遇到object语句时,它会读取类名,在将类名映射到类引用的表中查找,并在该类引用上调用虚拟TComponent.Create。这会调用实际类的虚构造函数,最终会得到该类型组件的实例,并开始填充其属性。