虛擬方法
虛擬方法在Delphi中利用關鍵字virtual定義。一個方法被聲明為虛擬方法後,在調用時,程式需要動態地確定需要調用的方法。
現在重新定義上面的方法。需要注意的是此處使用了關鍵字override,表示方法的重載。代碼如下所示:
type
TFigure = class
procedure Draw; virtual;
procedure Destroy
end;
procedure Tfigure.Draw;
begin
writeln('現在調用的是TFigure對象');
end;
type
TRectangle = class(TFigure)
procedure Draw; override;
procedure Destroy
end;
procedure TRectAngle.Draw;
begin
writeln('現在調用的是TRectangle對象');
end;
type
TEllipse = class(TFigure)
procedure Draw; override;
procedure Destroy
end;
procedure TEllipse.Draw;
begin
writeln('現在調用的是TEllipse對象');
end;
下面的代碼調用上述繪圖物件的Draw方法:
var
Figure: TFigure;
begin
Figure := TRectangle.Create;
Figure.Draw; // 調用TRectangle.Draw
Figure.Destroy;
Figure := TEllipse.Create;
Figure.Draw; // 調用TEllipse.Draw
Figure.Destroy;
end;
上述代碼中,第一次調用Figure.Draw時,當前對象是TRectangle類型;第二次調用Figure.Draw時,當前對象是TEllipse類型。
輸出如下:
現在調用的是TRectangle對象
現在調用的是TEllipse對象
動態方法
動態方法利用dynamic關鍵字實現,它的功能與虛擬方法基本類似,不同主要體現在內部實現。與對象虛擬方法建立入口不同的是,dynamic給方法賦了一個數字,並儲存相應代碼的地址。動態方法列表只包含新加的和覆蓋的方法入口,繼承的動態方法的匹配是通過尋找每一個祖先的動態方法列表(按與繼承“反轉的順序”)來實現,因此動態方法用於處理訊息(包括Windows訊息)。實際上,訊息處理過程的匹配方式與動態方法相同,只是定義方法不同。
動態方法沒有對象VMT(Virtal Method Table,虛擬方法表)的入口,它們減少了對象消耗的記憶體數量。匹配動態方法比匹配一般的虛擬方法慢。因此,如果方法調用很頻繁,最好將其定義為虛擬方法。
抽象方法
抽象方法利用關鍵字abstract實現,如果一個方法定義為抽象,則這個方法不需要在本類中實現。而在它的子類中,可以在重載方法中實現相關功能。
在下面代碼中,TFigure對象的Draw方法聲明為抽象,所以不需要實現TFigure.Draw方法,在它的子類中,子類資料根據各自不同的需求重載並實現這個方法。
type
TFigure = class
procedure Draw; virtual;abstract;
procedure Destroy
end;
type
TRectangle = class(TFigure)
procedure Draw; override;
procedure Destroy
end;
procedure TRectangle.Draw;
begin
writeln('現在調用的是TRectangle對象');
end;
type
TEllipse = class(TFigure)
procedure Draw; override;
procedure Destroy
end;
procedure TEllipse.Draw;
begin
writeln('現在調用的是TEllipse對象');
end;
如果一個類的抽象方法沒有被重載,則這個方法是不能被調用的,否則會產生調用抽象方法的內部Delphi錯誤。
方法重載
前面已經指出,通過override(方法重載)可以實現多態。方法重載即指多個方法可以享有相同的名字。通過在後代對象中聲明一個與祖先對象重名的方法,就可以重載一個方法。如果想使這個方法在後代對象中做和祖先對象一樣的工作,但是使用不同的方式,就可以重載這個方法。
如下幾種情況將導致重載失敗:
(1)祖先類中沒有要重載的方法。
(2)要重載的方法在祖先類中被聲明為靜態方法。
(3)要重載的方法的參數類型或個數與祖先類中不同。
方法繼承
Delphi利用關鍵字inherited實現方法之間的互相繼承。
如果inherited關鍵字後面沒有方法名,那麼當前方法就繼承祖先類中與它同名的方法;如果inherited關鍵字後面有方法名,則當前方法就繼承祖先類中指定的方法。
方法繼承經常用在構造方法中,以便子類能夠實現祖先類中的一些預設設定。
構造方法
構造方法是一種特殊的方法,它為新對象分配記憶體並且指向這個新的對象。Delphi中的每個類都有構造方法,用來初始化該類的一個新的對象。
建構函式利用關鍵字constructor來聲明,而建構函式的函數名可以任意選擇,但是Delphi中函數名一般採用Create。建構函式可以用多個,但是Delphi建議每個對象只定義一個建構函式。
Delphi在建構函式內部實現的處理過程包括:
(1)首先在記憶體中開闢一塊地區用於儲存物件。
(2)然後對這塊地區預設初始化設定。初始化,包括有序類型的欄位清零,指標類型和類類型的欄位設定為Nil,字串類型的欄位清為空白等。
(3)執行構造中使用者指定的動作。
(4)返回一個新分配的並初始化了的類類型執行個體。傳回值的類型必須就是類的類型。
建立一個對象的執行個體,需要先調用Create方法,然後建構函式把這個執行個體賦給一個變數。構造方法不返回任何資料類型,在構造方法的實現中,也可以進行方法重載,如下例所示:
type
TShape = class(TGraphicControl)
private
FPen: TPen;
FBrush: TBrush;
procedure PenChanged(Sender: TObject);
procedure BrushChanged(Sender: TObject);
public
constructor Create(Owner: TComponent); override;
destructor Destroy; override;
...
end;
M
constructor TShape.Create(Owner: TComponent);
begin
inherited Create(Owner); // Initialize inherited parts
Width := 65; // Change inherited properties
Height := 65;
FPen := TPen.Create; // Initialize new fields
FPen.OnChange := PenChanged;
FBrush := TBrush.Create;
FBrush.OnChange := BrushChanged;
end;
上述例子中,TShape 類重載了TGraphicControl的建構函式。在建構函式內部,TShape類首先繼承TGraphicControl的預設建構函式,實現一些常規設定,然後通過設定自己的一些特殊參數,實現自己的參數初始化,同時使自己與祖先類有所區別。
又一建構函式執行個體
delphi的建構函式的定義是:
constructor create;
delphi的解構函式的定義是:
destructor destroy;
解構函式是不能重載的,但是建構函式是可以重載的。
建構函式在重載的時候要在後面加“overload”,例如:
constructor create;overload;
constructor create(i:integer);overload;
注意,只有兩個建構函式以上才叫重載,只有一個就不用“overload;”了。
預設的建構函式是:constructor create; 如果有重載的話,那麼預設的建構函式後面也要加overload,正象上面的例子一樣。
delphi建構函式在類外定義在什麼位置呢?在implementation的後面。下面給出一個執行個體,可以從這個執行個體中看出建構函式的定義:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TMyForm1 = class(TForm1) //自訂一個TMyForm1類
public
constructor Create; overload; //建構函式有重載
constructor Create(I: Integer); overload; //重載一個建構函式
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
constructor TMyForm1.Create; //這裡定義建構函式
begin
inherited Create(nil); //inherited 表示調用父類的建構函式
end;
constructor TMyForm1.Create(I: Integer);
begin
inherited Create(nil);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
A: TMyForm1;
begin
A := TMyForm1.Create(1);
A.Show;
end;
end.