Delphi物件模型(Part III) (轉)

gugu99發表於2007-10-14
Delphi物件模型(Part III) (轉)[@more@]

 

模型 (PART III) :namespace prefix = o ns = "urn:schemas--com::office" />

 

 

Delphi對於物件導向的支援豐富而且強大。除了傳統的類和物件,Delphi還提供了介面,異常處理,多執行緒程式設計等特性。這一章節深入講解了Delphi的物件模型。讀者應當對標準的Pascal比較熟悉,並且對有關物件導向程式設計的基本法則有一定了解。

(本文的英文原文將Delphi與 Pascal統一表述為Delphi,可能有概念不清之嫌疑。但在大多數情況下,相信讀者能夠根據上下文來判定文中所述之Delphi的具體含義——譯者注。)

 

構造器(Constructor)

每一個類都有一個或多個可能是自基類繼承而來的構造器。按照慣例,構造器通常命名為Create,但你也可以使用其他名稱。有些構造器以Create打頭,為了傳遞更多的資訊,被命名為諸如CreateFromFile或者CreateFromStream這樣的名字。通常情況下,使用”Create” 這個名字就可以了,因為你可以使用過載來定義多個相同名字的構造器。另一個原因是為了保持與C++Builder的相容。因為C++不允許構造器使用不同名稱,因此你必須使用過載來定義多個構造器。

構造器

構造器是物件方法和類方法的混合體。你可以使用一個物件引用或者一個類引用來呼叫它。Delphi會傳遞一個附加的隱含的引數來指示它如何被呼叫。假如使用一個類引用來呼叫構造器,Delphi會呼叫類的NewInstance方法以獲得該類的一個新的例項。然後,構造器繼續處理並且初始化物件。構造器自動引入一個try-except模組,當構造器中觸發異常時,Delphi將自動呼叫析構器。

使用物件引用來呼叫構造器時,Delphi不會引入try-except塊,也不會呼叫NewInstance方法。相反,它象呼叫普通方法一樣呼叫構造器。這個特性允許你呼叫繼承的構造器而無需增加額外的開銷。

提示
一個常見的錯誤是嘗試使用物件引用來建立一個物件,而不是用一個類引用來建立物件並將它賦值給一個物件引用:

var


  Account: TSavingsAccount;


begin


  Account.Create;  //錯誤


  Account := TSavingsAccount.Create; //正確


Delphi的特性之一是你可以控制在何時呼叫,如何呼叫,以及是否需要呼叫一個繼承的構造器。這個特性使你可以構建功能強大的類,但在一定程度上也使得錯誤容易發生。

Delphi總是先構造派生的類,僅當派生類呼叫了繼承的構造器時才去構造基類。在C++中次序相反,從祖先類開始構建,最後才是派生的類。因而,假如有類C繼承於B,而B繼承於A,那麼Delphi先是構建C,然後是B最後是A.C++先構建A,然後B,最後C。

虛方法和構造器

另一個介於C++和Delphi之間的一個很大的不同是,在C++中,構造器總是根據已經被建立的類的虛方法表來執行。而在Delphi中,虛方法代表了所有派生類的內容,即使基類還沒有被建立。因此,當你書寫一個可能被構造器呼叫的虛方法時一定要小心。否則,物件可能還沒有完全建立時該方法就被呼叫了。為了預防這種情況,你應當覆蓋AfterConstruction方法,在其中填寫需要等到物件被完全建立後才能的程式碼。假如要覆蓋AfterConstruction,別忘了呼叫inherited方法。

一個構造器可以呼叫另一個構造器。Delphi能夠區分該呼叫是否來自於物件引用,因此呼叫構造器與呼叫普通方法相同。呼叫另一個構造器最常見的理由是把初始化程式碼放在一個單一的構造器中。例2-7顯示了宣告和呼叫構造器的幾種不同的方法。

2-7:宣告和呼叫構造器

type


  TCustomer = class ... end;


  TAccount = class


  private


  fBalance: Currency;


  fNumber: Cardinal;


  fCustomer: TCustomer;


  public


  constructor Create(Customer: TCustomer); virtual;


  destructor Destroy; overr;


  end;


  TSavingsAccount = class(TAccount)


  private


  fInterestRate: Integer; // Scaled by 1000


  public


  constructor Create(Customer: TCustomer); override; overload;


  constructor Create(Customer: TCustomer; InterestRate: Integer);


  overload;


//注意:TSaveingAccount不需要再定義一個析構器。


//它只是簡單的繼承了TAccount的構造器


 


 end;



var


  AccountNumber: Cardinal = 1;



constructor TAccount.Create(Customer: TCustomer);


begin


  inherited Create;  // Call TObject.Create.


  fNumber := AccountNumber;  // Assign a unique account number.


  Inc(AccountNumber);


  fCustomer := Customer;  // Notify customer of new account.


  Customer.AttachAccount(Self);


end;



destructor TAccount.Destroy;


begin


 


 //如果在設定fCustomer欄位之前構造出錯,則該欄位為nil。


//僅當Customer不為nil才釋放account。


  if Customer <> nil then


  Customer.ReleaseAccount(Self);


  //呼叫TObject.Destroy.


  inherited Destroy;


end;



const


  DefaultInterestRate = 5000;  // 5%, scaled by 1000



constructor TSavingsAccount.Create(Customer: TCustomer);


begin


  //呼叫同類的另一個構造器


  Create(Customer, DefaultInterestRate);


end;



constructor TSavingsAccount(Customer: TCustomer; InterestRate:Integer);


begin


  //呼叫TAccount.Create


  inherited Create(Customer);


  fInterestRate := InterestRate;


end;


析構器(Destructor)

析構器和構造器一樣也隱藏了一個附加的引數。第一次呼叫時,該附加引數被置為True。這使得Delphi呼叫FreeInstance來釋放物件。如果該析構器呼叫了繼承的析構器,那麼Delphi將這個隱含的引數設定為False以防止繼承的析構器再次釋放同一個物件。

提示:
一個類通常有一個析構器名為Destroy。Delphi允許宣告多個析構器——但這一特性並未帶來什麼 方便之處。定義多個析構器通常容易使人感到迷惑並且沒有什麼實際意義。

在Delphi執行析構器中的程式碼之前,它先呼叫虛方法BeforeDestruction。你可以覆蓋該方法以確保在析構以前有些事務被處理掉。這個特性使你能寫出的類程式碼,而不必擔心派生類會在何時呼叫基類的析構器。

提示:
定義一個類時,你可能需要覆蓋名為Destroy的析構器方法,但是不要重新定義Free方法。釋放一個物件時,你要呼叫的是Free方法而不是析構器。這一區別非常重要,因為Free首先檢查物件引用是否為nil,只有引用非空時才呼叫Destroy方法。只在某些特定的場合,才需要重新定義Free方法(比如很少用用到的單元VirtIntf中的TInterface類),因為可能呼叫Free比Destroy更重要。

假如構造器方法和AfterConstruction方法引發了異常, Delphi會自動呼叫析構器。寫一個析構器時,必須意識到正在被撤銷的物件有可能沒有被完全的建立。Delphi確保所有的欄位初始值為空,但假如在構造器中引發了異常,則可能導致某些欄位已被初始化而有些未被初始化。如果構造器直接釋放物件和指標,那麼……其實不必擔心這一點,因為Free方法和FreeMem過程都能自動檢查指標是否為空。如果構造器呼叫其他方法,那麼也會事先檢查指標是否為空。

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-976386/,如需轉載,請註明出處,否則將追究法律責任。

相關文章