2010-12-07 113 views
3

我对Delphi中可用的虚拟构造函数没有任何经验。我考虑使用虚拟构建函数的类层次重置实例为初始状态是这样的:使用虚拟构造函数重置为初始状态

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; 
+0

为什么不重新将“创建”重命名为“程序重置;虚拟”之类的东西?并称之为无处不在?这样你就可以确定它正在做你想要的东西。 – himself 2010-12-07 14:40:57

回答

3

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

即使你在控制,我仍然建议反对它。 这不是惯用的德尔福;其他任何人阅读你的代码(甚至可能是你,从现在开始的几个星期或几个月)将会被你非标准的构造函数所困惑 - 至少在一开始就是这样。这是不值得的麻烦。如果调用Bar函数应该释放A对象的所有权并创建一个新实例,然后使用清楚的名称编写函数。

1

Rob的这种权利很可能会让人感到困惑,并且将代码移动到初始化例程是一个好主意。如果你想知道,虚拟构造函数的主要目的是完全不同的:更容易支持“工厂”风格的对象创建。

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

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