2010-12-07 68 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。這將調用實際類的虛擬構造函數,並以該類型組件的實例結束,並開始填充其屬性。