DELPHI面向對象參考
陳奇 2005-07-21
一、類和對象
類是對象的類型,是創建對象的模板。一個類可以創建多個對象,而一個對象總是屬于某個類。類具有內部的屬性(狀態)和行爲(操作)。
對象是類的實例,具有區別于同類其他對象的屬性集合。
對象的聲明存放于堆棧,對象的引用存放于堆。
二、類的方法分類
1、 普通方法
不加任何修飾的方法爲普通方法。普通方法必須調用類的實例進行訪問。即必須
建類的對象,調用方式爲:對象.方法,聲明方式爲:
procedure[function] 方法名(參數表)[:返回值];
2、 構造方法
構造方法用于創建類的實例,調用後返回類的句柄。構造方法可以有多個版本。聲明方式是:
constructor 構造方法名(參數表);
3、 析構方法
析構方法用于銷毀類的實例,一般不建議直接調用析構方法,而采用調用對象.Free的方式進行對象釋放。聲明方式爲:
destructor 析構方法名(參數表);
4、 類方法
類方法屬于一個類,在運行時即存在于內存中。可使用類.方法的方式進行調用,即不需要創建類的實例。聲明方式是在普通方法前加class:
class procedure[function] 方法名(參數表)[:返回值];
5、 消息處理方法
消息處理方法和一個唯一的消息ID進行關聯,用于響應動態分派的消息。聲明方式:
procedure 方法名(消息變元);message 消息ID;
三、多態、繼承、重載
1、 靜態方法
靜態方法由對象的類決定。屬于“早期聯編”,即在編譯階段就決定了方法的實現版本。一個類的實例可創建爲其他類的實例,但是調用到同名方法時,使用的方法是聲明該實例的類的靜態方法,聲明方式:
procedure[function] 方法名(參數表)[:返回值];
2、 虛擬方法
虛擬方法可實現“後期聯編”,即在程序運行時可動態調用不同的方法版本,實現多態。所有類的虛擬方法在內存中建立了一張VMT(虛擬方法表),在調用時動態定位方法函數的位置。比動態方法多占用內存空間,但是速度較快。聲明方式:
procedure[function] 方法名(參數表)[:返回值];virtual;
3、 動態方法
虛擬方法可實現“後期聯編”,即在程序運行時可動態調用不同的方法版本,實現多態。本類的動態方法在內存中建立了一個DMT(動態方法表),在調用時根據動態方法唯一的編號定位方法地址。比虛擬方法少占用內存,但是速度較慢(因爲可能用到祖先類的動態方法)。聲明方式:
procedure[function] 方法名(參數表)[:返回值];dynamic;
4、 抽象方法
抽象方法不提供方法的實現腳本。只提供一個方法的簽名(方法名稱、參數表、返回值)。一般在高級別類中使用抽象方法。派生類對抽象方法進行覆蓋、重載實現抽象方法腳本。使用抽象方法,必須創建實現了抽象方法的類(一般爲派生類)才可使用。因爲抽象方法也屬于“後期聯編”,因此必須和虛擬方法、動態方法結合,聲明方式:
procedure[function] 方法名(參數表)[:返回值];virtual;abstract;
procedure[function] 方法名(參數表)[:返回值];dynamic; abstract;
抽象方法提供了一種從高層次視圖觀察對象的方式
5、 方法覆蓋
在父類中生命的靜態方法、虛擬方法、動態方法,都可在派生類中進行同名簽名登記。這將覆蓋父類的這些方法。提供更特殊的功能,聲明方式:
procedure[function] 方法名(參數表)[:返回值];override;
方法的覆蓋提供了對類的多態性
6、 方法重載
在父類中生命的靜態方法、虛擬方法、動態方法,都可在派生類中進行同名簽名登記,但是需要不同的參數表。這將重載父類的這些方法。提供更特殊的功能,聲明方式:
procedure[function] 方法名(參數表)[:返回值];overload;
方法的重載提供了對類的擴充性
四、reintroduce、self、is、as
1、 reintroduce
當父類中以定義了一方法,派生類再定義同簽名的方法將會隱藏父類的方法,如果不希望這種結果出現,可在派生類定義方法時,加此標志,聲明方式:
procedure[function] 方法名(參數表)[:返回值];reintroduce;
2、 self
self代表了實例對象自身。類的所有數據成員和函數成員都隱含存在于with self do結構範圍內。使用方法:
self.Edit1.text:=’’;
3、 is
is用于進行實例對象的類型檢查,以Boolean返回是否是該類實例(或派生類實例),使用方法:
if Edit1 is Tedit then …
4、 as
as用于進行對象的強制類型轉換,一般適用于子類向父類的轉換(特殊→一般),而從父類到子類的轉換可能失敗。在使用時,可結合is進行判斷,使用方式:
if Sender is Tedit then (Sender as TEdit).Text:=’’;
五、類內部成員可見性
1、 類具有private、public、protected、published共4中訪問屬性。訪問屬性是指其他類對該類對象的可操作性,可讀寫性,以及其他類對本類中類方法(函數)的可操作性
2、 private:本類內部使用;聲明在同一單元的其他類可使用
3、 public:本類、本類派生類、其他類都可訪問
4、 protected:本類、本類派生類可訪問。其他類不可訪問
5、 published:所有類都可訪問。
綜合舉例:
TClass1=class
private
{內部數據/狀態儲存聲明}
FName: string;
FAge: Integer;
{內部屬性寫方法聲明}
procedure SetAge(const Value: Integer);
protected
{保護虛方法聲明}
procedure Eat;virtual;
public
{公有屬性/狀態儲存聲明}
Sex: string;
published
{公共屬性發布聲明}
{構造函數}
constructor create;
{具有讀/寫方法的屬性聲明}
property Name:string read FName write FName;
property Age: Integer read FAge write SetAge;
end;
TClass2=class
private
FSex: string;
published
constructor create;
end;
TClass11=class(TClass1)
public
{覆蓋了父類中同名的方法,提升了方法的可見性}
procedure Eat;override;
end;
{ TClass1 }
constructor TClass1.create;
begin
end;
procedure TClass1.Eat;
begin
end;
procedure TClass1.SetAge(const Value: Integer);
begin
FAge := Value;
end;
{ TClass2 }
constructor TClass2.create;
var
c2:TClass2;
begin
c2:=TClass2.create;
c2.FSex:='';
FreeAndNil(c2);
end;
{ TClass11 }
procedure TClass11.Eat;
begin
inherited;
end;
UML圖-類圖:
6、 派生類可提升父類的可見性,卻不可降低父類的可見性
六、對象、對象引用、類引用、參數傳遞
1、 對象之間通過消息傳遞(參數),進行互操作,使用其他類提供的服務(方法組合);消息即對另一對象方法的調用或屬性讀寫
2、 對象分配在堆中、普通數據類型分配在棧中
3、 對象名代表了該對象在棧中的位置,該位置存儲的是對象在堆中的實際地址;普通變量名代表了該變量在棧中的位置,該位置存儲的是具體數據,而該數據可能是其他變量/對象的地址
4、 值參傳遞:傳遞的是具體的數值,進行處理後不會改變原值,其實傳遞的是該數據的一個副本
5、 引用傳遞:傳遞的是對該變量/對象的地址引用,處理後可能會改變原值,傳遞的是同一個變量/對象的地址
6、 類引用:類的類,形式爲“class of type”,其中type代表該類可引用的類元類型。
七、對象的創建、使用、銷毀
1、 創建:Create是 Tobject提供的默認構造函數,若從Tobject繼承創建的類,自動繼承該方法
2、 銷毀:Destroy是Tobject提供的默認析構函數,若從Tobject繼承創建的類,自動繼承該方法
3、 使用:可使用if Assigned (對象名) 判斷該對象是否存在;使用FreeAndNil(對象名)釋放對象
4、 克隆:繼承自Tpersistent的類對象都具有克隆功能。使用對象2.Assign(對象1)的方式克隆
5、 對象的屬主:當對象擁有屬主時,其生命周期由屬主對象進行管理,無屬主的對象需要進行手工管理。
6、 對象的創建:先繼承父類創建,再完成自身的創建
7、 對象的釋放:先釋放自身,在完成父類的繼承釋放
八、類及對象間的關系
1、 繼承:子類繼承了父類的所有保護、公有、發布部分的數據成員及函數/過程成員
2、 重載:不是類的特有。提供一個同名但參數不同的函數/過程,具有多個實現版本
3、 覆蓋:子類通過繼承父類的函數/過程,重新定義了功能實現
4、 引用:一個對象內部定義了另一個對象變量,即爲引用關系
5、 合成:對象內的各組成部分依賴于某一主體屬性而同生共滅
6、 聚合:對象內的各組成部分屬于零散的簡單組合關系,使用不同的服務組合成一個整體的功能
九、接口
1、 接口:具有某種特定的屬性及函數/過程簽名的定義,而沒有實現。不具備內部數據成員。功能的調用是通過創建實現其功能簽名的派生類完成的
2、 接口必須具備3個方法:_AddRef/_Release/QueryInterface,最簡單的方式是從TinterfacedObject繼承
3、 接口使用演示:
IInterface=interface
['{02960574-2025-46C3-9882-F79C3C67EA99}']
function GetName:string;
procedure Eat;
end;
TPerson=class(TInterfacedObject,IInterface)
private
FName: string;
public
function GetName:string;virtual;
procedure Eat;dynamic;
procedure SayHello;virtual;abstract;
published
constructor create;
destructor destory;
property Name:string read FName write FName;
end;
TChinese=class(TPerson,IInterface)
public
procedure SayHello(str:string);overload;
procedure SayHello;overload;override;
published
constructor create;
destructor destory;
end;
{ TPerson }
constructor TPerson.create;
begin
ShowMessage('TPerson.create');
end;
destructor TPerson.destory;
begin
ShowMessage('TPerson.destory');
end;
procedure TPerson.Eat;
begin
ShowMessage('TPerson.Eat');
end;
function TPerson.GetName: string;
begin
result:='TPerson.GetName';
end;
{ TChinese }
procedure TChinese.SayHello(str: string);
begin
ShowMessage('TChinese.SayHello('+str+')');
end;
constructor TChinese.create;
begin
ShowMessage('TChinese.create');
end;
destructor TChinese.destory;
begin
ShowMessage('TChinese.destory');
end;
procedure TChinese.SayHello;
begin
//inherited;
ShowMessage('TChinese.SayHello');
end;
procedure TForm1.Button2Click(Sender: TObject);
var
FMan:TPerson;
begin
FMan:=TChinese.create;
FMan.SayHello;
FMan.Free;
end;
4、
十、