2009-08-06 22 views
2

如果我寫類的類型和構造函數調用

type 
    MyClass = class of TMyClass; 
... 
Obj := MyClass.Create; 

正確的構造函數(一個在TMyClass)被調用。

如果我寫

var 
    ClassVar : TClass; 
... 
ClassVar := TMyClass; 
Obj := ClassVar.Create; 

只有TObject的構造函數被調用。

爲什麼?這兩個版本有什麼區別?我可以在第二個場景中強制使用TMyClass構造函數嗎?

回答

11

TClass在system.pas中聲明爲「Class of TObject」。被調用的構造函數是在編譯時決定的,編譯器知道的是你正在使用的基類。它不知道運行時變量的值是什麼,所以它必須默認爲基類。如果你使用的是TClass,那麼你的基類是TObject。

如果您使用的是類變量,我認爲您有某種類型的變體,並且您正在嘗試實施一個工廠。如果您想確保在運行時基於類變量的值調用正確的構造函數,而不是編譯時代碼中包含的東西,則需要一個虛擬構造函數。

​​

使用TMyClass代替TClass作爲你的類變量,現在的編譯器將生成到TMyBaseObject.Create一個電話,這是虛擬的。確保所有派生類都覆蓋基礎構造函數,並且最終在運行時調用正確的類。

+0

+1謝謝!構造函數是虛擬的嗎?具體來說,TObject.Create是不是虛擬的? – jpfollenius 2009-08-06 18:17:53

+1

可能是因爲它不需要虛擬。首先,虛擬方法調用只能使用相同的簽名,而大多數構造函數至少需要一個參數。其次,如果您以這種方式使用工廠模式,那麼您可能需要特定類的後代。 – 2009-08-06 18:21:38

2

我建議你看看覆蓋由TObject引入的AfterConstruction方法來使多態性像這樣的工作。

每個類定義都可以引入一個新的構造函數,並帶有它自己的一組參數。一個類變量只知道構造函數,如果它是一個變量的基類。這是完全可能的,因爲構造函數既不是虛擬也不是重寫。你可以在你的基類上標記虛構的構造函數,並且標記所有的降序類覆蓋,這將阻塞參數列表。 (我認爲如果你忘記'覆蓋'編譯器會警告你的新構造函數隱藏了虛擬構造函數。)

+0

這不會解決基本問題。沒有虛擬構造函數,他總是最終創建TObject對象,而不是他正在尋找的類。 – 2009-08-06 18:18:54

+0

你試過了嗎?給定問題中的代碼和TSomeOtherObject = class(TMyBaseObject),如果將Someclass:TMyClass設置爲TSomeOtherObject,它應該保存指向類數據的內存指針,包括重寫的構造函數。 (我認爲,應該自己嘗試......) – 2009-08-07 06:08:28

+0

噢,好吧,如果他使用更具體的類變量。我以爲你的意思是他可以使用一個TClass和一個AfterConstruction覆蓋來獲得從TObject降序的任何事情的正確行爲。 – 2009-08-07 13:19:44

4

TObject.Create不是虛擬的,你需要將ClassVar聲明爲具有虛擬構造函數的類的一個類型。

-3

或者從已經具有虛擬構造函數的TComponent中下載它。

+0

-1 ...加上我並不需要的很多開銷。令人困惑的是:「組件是具有以下功能的持久對象:IDE集成,所有權,流媒體和歸檔,COM支持」(引自Delphi幫助)......這不是我真正想要的東西。 – jpfollenius 2009-08-07 06:53:17

+0

從未有過TComponent的速度問題。並且對於COM支持,我知道如果後代是COM對象(VCLComObject字段)的包裝,它會引用couting。所有權是需要創建子對象時的保佑,當子對象死亡時必須銷燬子對象。 IDE集成意味着您可以將其註冊到調色板上。所以,我使用TComponent作爲我的對象的基礎,是的。 – 2009-08-07 08:51:55

+0

如果一個類是一個組件,則它只應從TComponent下降。 – 2009-08-07 11:02:22

相關問題