2014-10-01 76 views
2

我想要一個從具有自定義構造函數的BaseForm派生的MainForm。由於這是Mainform,因此通過在* .dpr文件中調用Application.CreateForm(TMyMainForm,MyMainForm)來創建它。但是,我的自定義構造函數在窗體創建過程中未被調用。以自定義構造函數作爲mainform的Delphi窗體?

很明顯,它工作正常,如果我打電話MyMainForm:= TMyMainForm.Create(AOwner)。我可以不使用具有自定義構造函數的窗體作爲主窗體嗎?

TBaseForm = class(TForm) 
    constructor Create(AOwner:TComponent; AName:string);reintroduce; 
end; 

TMyMainForm = class(TBaseForm) 
    constructor Create(AOwner:TComponent);reintroduce; 
end; 

constructor TBaseForm.Create(AOwner:TComponent); 

begin; 
    inherited Create(AOwner); 
end; 

constructor TMyMainForm.Create(AOwner:TComponent); 

begin; 
    inherited Create(AOwner, 'Custom Constructor Parameter'); 
end; 

回答

8

Application.CreateForm()不能調用reintroduce「d構造。創建新對象時,它調用TComponent.Create()構造函數,並期望多態性調用任何派生的構造函數。通過reintroduce'你的自定義構造函數,你不是多態呼叫鏈的一部分。 reintroduce公開了一種全新的方法,其名稱與繼承方法相同,但與其無關。

要做你正在嘗試的,不要使用reintroduce你的構造函數。創建您的基本形式單獨構造,然後讓你的MainForm override標準的構造函數來調用定製基構造函數,如:

TBaseForm = class(TForm) 
    constructor CreateWithName(AOwner: TComponent; AName: string); // <-- no reintroduce needed since it is a new name 
end; 

TMyMainForm = class(TBaseForm) 
    constructor Create(AOwner: TComponent); override; // <-- not reintroduce 
end; 

constructor TBaseForm.CreateWithName(AOwner: TComponent; AName: string); 
begin; 
    inherited Create(AOwner); 
    // use AName as needed... 
end; 

constructor TMyMainForm.Create(AOwner: TComponent); 
begin; 
    inherited CreateWithName(AOwner, 'Custom Constructor Parameter'); 
end; 
+1

大多數時候,所有人都試圖通過這種方法來做的是通過構造函數初始化派生類中的成員。我不推薦這個。相反,您也可以在派生表單創建後定義公共屬性並對它們進行初始化。這是額外的一兩行代碼,但是又如何? – 2014-10-01 06:26:09

+2

帶參數的構造函數的優點是你**必須傳遞一些東西,所以你不能忘記傳遞所需的設置。設置屬性可以被遺忘。這不是因爲人們想要節省輸入幾行,而只是因爲它是更好的策略,IMO。 – 2014-10-01 07:32:03

+0

這個計劃的原因正是由Rudy指出的,@RudyVelthuis我的意圖是擁有一個共同的基本形式,它具有背景,處理NCHitTest,記住最後的位置,大小等(從註冊表中讀取/寫入)並導出所有未來的項目從那。有沒有比上述策略更好的方法? – ss2006 2014-10-01 09:03:14

1

爲了使表成爲VCL主要形式,它必須創建通過致電Application.CreateForm。這又調用TComponent中聲明的虛擬構造函數。所以,沒有辦法得到一個不同的構造函數來調用VCL主表單。

一種選擇是由雷米提出的。覆蓋TComponent中聲明的構造函數,並調用另一個傳遞額外參數的構造函數。這可以是同一個類中的構造函數,也可以是基類中的繼承構造函數。

這裏的另一個選擇是在基類上使用抽象類方法。例如,

type 
    TMainFormBase = class(TForm) 
    protected 
    class function ProjectName: string; virtual; abstract; 
    class function RegKeyPath: string; virtual; abstract; 
    end; 

在您的派生類中,您將覆蓋這些抽象方法。不用在構造函數中設置屬性,基本窗體類中的代碼就可以調用這些方法。當然,如果你需要在構造函數中工作,你可以完美地從構造函數中調用這些方法。

就我個人而言,我對添加新的構造函數給已經具有虛擬構造函數的類有偏見。虛擬構造函數範式引導你使用那個單一的虛擬構造函數,而沒有別的。如果你開始在層次結構下面添加不同的構造函數,那麼在虛擬化實例化時調用錯誤的構造函數會導致麻煩,這很容易。

相關問題