2011-06-12 76 views
2

我有以下的超類:問題指針傳遞到一個構造作爲參數

unit DlgDefaultForm; 

type 
    TDefaultFormDlg = class(TForm) 
    published 
    constructor Create(AOwner: TComponent); reintroduce; virtual; 
    end; 

    FormCreateFunc=function(AOwner: TComponent):TDefaultFormDlg; 

其由一堆形式下降如下:

unit Form1 

type 
    TForm1 = class(TDefaultFormDlg) 
    published 
    constructor Create(AOwner: TComponent); override; 
    end; 

和創建如下:

unit MainForm; 

procedure ShowForm(FormCreate:FormCreateFunc); 
begin 
    (do some stuff) 
    FormCreate(ScrollBox1); 
end; 

當我運行

ShowForm(@TForm1.Create); 

發生兩件事情:

  1. 當我踏進TForm1.Create,AOwner =零,即使在ShowForm沒有。

  2. 我在下面一行得到EAbstractError:

    unit Forms; 
    (...) 
    constructor TCustomForm.Create(AOwner: TComponent); 
    begin 
        (...) 
        InitializeNewForm; //EAbstractError 
        (...) 
    end; 
    

我在做什麼錯?

編輯:這當然不是我的確切代碼。

回答

2

您沒有正確使用虛擬構造函數。嘗試這樣:

type 
    TDefaultFormDlgClass = class of TDefaultFormDlg; 

function Show(FormClass: TDefaultFormDlgClass; AOwner: TComponent): TDefaultFormDlg; 
begin 
    Result := FormClass.Create(AOwner); 
end; 

... 
var 
    FormClass: TTDefaultFormDlgClass; 
... 
FormClass := ???;//this is where you specify the class at runtime, e.g. TForm1 
MyForm := Show(FormClass, MainForm); 

順便說一句,我不認爲你需要在你列出的代碼中重新引入構造函數。

+0

啊,我想知道如果我可以在變量中保存類的類型。我會試試這個。 – boileau 2011-06-12 11:28:27

+0

看起來不錯。我在關閉表單時仍然遇到一些錯誤,但我沒有關係。 – boileau 2011-06-12 11:35:34

8

Delphi構造函數帶有一個隱藏的額外參數,它指示了兩件事情:是否需要調用NewInstance以及隱式第一個參數(Self)的類型是什麼。當您從類或類引用調用構造函數時,實際上需要構造一個新對象,並且Self參數的類型將是實際的類類型。當您從另一個構造函數調用構造函數時,或者在調用繼承的構造函數時,則該對象實例已經創建並作爲參數Self傳遞。隱藏的額外參數充當Boolean標誌,其爲True用於分配新實例,但False用於構造函數的方法式調用。因此,您不能簡單地將構造函數存儲在方法指針[1]位置並期望其工作;調用方法指針不會爲隱藏的額外參數傳遞正確的值,並且會中斷。您可以通過顯式聲明參數來繞過它,並進行一些類型轉換。但通常直接使用元類(類引用)更爲理想且不易出錯。

[1]這是你的代碼的另一個問題。你正試圖將一個方法指針存儲在一個函數指針位置中。你可以做到這一點,但仍然可以工作,但是你需要明確地聲明Self,並且在分配時還需要傳遞元類作爲第一個參數(以及爲隱式傳遞True旗)。方法指針烘烤第一個參數並自動傳遞它。爲了使這一切明確的,相當於TComponent.Create函數指針是一樣的東西:

TComponentCreate = function(Self: Pointer; AOwner: TComponent; DoAlloc: Boolean): Pointer; 

Self是一個指針,在這裏,因爲它可能是TComponentClass類型,或TComponent類型,取決於是否DoAlloc是真的還是假的。

+0

感謝您的信息! – boileau 2011-06-12 11:48:46

2

基於來自Barry的信息,我測試了這個代碼。 TSample是一個帶有無參構造函數的簡單類。所有你需要的是指向構造函數(@ TSample.Create)的指針和類的類型(TSample)。如果你有一個hashmap key = TClass,value = Pointer ctor,你可以創建任何註冊類型。

type 
    TObjectCreate = function(Self: TClass; DoAlloc: Boolean): TObject; 

var 
    aSample : TSample; 
begin 
    aSample := TSample(TObjectCreate(@TSample.Create)(TSample, true));