Delphi中的類和物件 (轉)

worldblog發表於2007-12-14
Delphi中的類和物件 (轉)[@more@]

  談談中的類和
1.登不了大雅之堂地理解幾個概念
  說到類和物件,我們不能不提及這樣幾個概念:類,物件,例項。就我個人覺得可
以這樣來理解:物件指的是泛稱,自然界的任何實體都可以看成一個物件;而類則是
以這些物件某些特徵而分成的一系列的種類;例項則是特指屬於某一個類的一個物件。
好啦,這些大道理我就不用多說了。不如來一個“背道而馳”的作法,我們用Delphi
code 來闡述這些外國人提出的一些令我們中國人不好理解的概念吧:
var
  ABtn:TButton;
義ABtn是屬於TButton類的一個物件,但ABtn不能說是一個例項,因為它還沒有
建立,所以我們說這是定義了一個物件,如果說定義了一個例項,多多少少有
些不夠確切。:)
begin
  ABtn:=TButton.Create(Self);//建立一個TButton的例項
  ABtn.Caption:='物件';
  ABtn.Free;
end;

2.物件是一個地地道道的指標
  從物理角度來看,物件就是一段地址空間,這段地址空間的標誌就是我們定義的
類“變數”。所以我們可以把物件看成一個類的指標。大家知道,要訪問一個指標就
必須對指標初始化。物件的既然是一個指標,也必須對它進行初始化。如何初始化呢?
還是說指標的初始化吧。對於一個指標可以有以下兩種方法來進行初始化:
(一)直接分配
var
  Pint:^Integer;
begin
  new(Pint);
  Pint^:=12;
  Dispose(Pint);
end;
(二)指向別的已分配空間的變數
var
  Pint:^Integer;
  i:integer;
begin
  i:=12;
  Pint:=@i;
end;
有趣的是,物件這種“指標”也有兩種方法初始化
(一)直接分配
var
  AForm:TForm;
begin
  AForm:=TForm.Create(Self);
  AForm.ShowModal;
  AForm.Free;
end;
(二)指向別的已分配空間的例項
var
  AForm:TForm;
begin
  AForm:=Self;
  AForm.Caption:='知道了嗎?為什麼會這樣呢';
end;
個AForm和它所指向的Form例項共用同一段地址單元,所有對AForm操作都將反應
它所對應的Form例項之上。
說到這,我們就很好解釋為什麼過程()的物件引數傳遞時,象這樣這的格式:
(一)procedure SetEdit(var Edit:TEdit);
  begin
  Edit.Text:='11';
  end;

(二)procedure SetEdit(Edit:TEdit);
  begin
  Edit.Text:='11';
  end;
效果是一樣的了。(一)是把一個TEdit實體作為引數引用的形式進行引數傳遞,(二)是
把一個TEdit的物件“指標”作為引數傳遞。

3.類可以理解成一種特殊的資料型別
  我們知道資料型別可以進行強制型別轉化,類即然可以理解成一種資料型別,那
麼它也應該可以進行類型別轉。比方如下程式碼為一個按鈕(Button1)的單擊事件:
(一)
procedure TForm1.Button1Click(Sender: T);
var
  ACaption:String;
begin
  ACaption:=TButton(Sender).Caption;//Sender從TObject轉化到TButton
  ShowMessage(Format('You clicked ''%s'' !',[ACaption]));
end;
在這段程式碼中,Sender是一個TObject型物件,我們把它強制轉化為TButton型別。如你
看得不清楚,可以參照一下我們通常的資料型別的轉化:
(二)
procedure TForm1.Button1Click(Sender: TObject);
var
  S_Str:String;
  P_Str:PChar;
begin
  S_Str:='I love China!';
  P_Str:=PChar(S_Str);
  S_Str:='';
  S_Str:=String(P_Str);
  ShowMessage(S_Str);
end;
但是在面對物件的設計過程中,強調的是性,如(一)的強制型別轉化存在著不
安全性。如下的程式碼,依然是寫Button1.OnClick事件:
(三)
procedure TForm1.Button1Click(Sender: TObject);
begin
  TCanvas(Sender).Brush.Color:=clRed;
end;
一下,就會出錯。這樣豈不是違背了面對物件的程式設計的宗旨了嗎?沒有,即然
是類,就應該有類特定的類強制轉化方法,改(三)的方法如下:
(四)
procedure TForm1.Button1Click(Sender: TObject);
begin
  (Sender as TCanvas).Brush.Color:=clRed;
end;//用as來轉化,as就可以把錯誤抓住,不會影響程式的正常執行。
說到這我順便提一下VB吧,如果學過VB的人可能覺得其中的陣列比較爽,尤其是在
編寫象計算器這樣的程式時。但Delphi給我們什麼呢?答案是Delphi也能簡潔的開
發出這樣的程式。如是操作:在窗體上放一個Edit和十個Button,把Button.Caption分
別設為'0','1','2',...'9',然後寫一個按鈕的OnClick事件如下:
(五)
procedure TForm1.Button1Click(Sender: TObject);
begin
  Edit1.Text:=Edit1.Text+(Sender as TButton).Caption;
end;
把別的Button的OnClick事件都關聯到Button1Click上,執行程式。拍拍手!這樣計算器
程式的雛形就具備了。我們用Delphi的類型別轉化,開發出來類似VB中的控制元件陣列功能
的程式也是很棒的嘛!:)

4.抽象類和它的例項
  Delphi中有一種類為抽象類,你不能天真的直接為它建立一個例項。如:TStrings
類。如下程式碼:
(一)
var
  StrLst:TStrings;
begin
  StrLst:=TStrings.Create;
  StrLst.Add('I love Japan!');
  StrLst.Free;
end;
這是不對的。那如何為諸如TStrings這樣的抽象類構造例項呢?答案是藉助它的非抽
象子類。我們知道TStrings有一個TStringList非抽象子類。我們就可以這樣作:
(二)
var
  StrLst:TStrings;
begin
  StrLst:=TStringList.Create;//藉助其子類的構造器,對StrLst進行子類化
  StrLst.Add('I love China!');
  StrLst.Free;
end;
(三)
var
  StrLst:TStringList;
begin
  StrLst:=TStringList.Create;
棄吧,不要再用抽象類,完全用它的“兒子”來你的事吧 
  StrLst.Add('I love China!');
  StrLst.Free;
end;

5.類是一種對資料和操作高度的封裝機制
(一)資料封裝
unit Unit2;

interface
type
  TEmployee=class
  private
  FName:String;
  public
  Constructor Create;
  function  GetName:String;
  procedure SetName(AName:String);
  end;
implementation

{ TEmployee }

constructor TEmployee.Create;
begin
  FName:='BlazingFire';
end;

function TEmployee.GetName: String;
begin
  Result:=FName;
end;

procedure TEmployee.SetName(AName: String);
begin
  FName:=AName;
end;

end.
如上程式碼,我們就用了一個過程SetName和一個函式GetName對私有變數FName進行完全的
封裝。我們要對FName操作就只有這樣:
uses
  unit2;
procedure TForm1.Button1Click(Sender: TObject);
var
  AEmployee:TEmployee;
begin
  AEmployee:=TEmployee.Create;
  AEmployee.SetName('Rose');//利用SetName來設定FName
  MessageBox(Handle,PChar(AEmployee.GetName),'Empoyee',0);
  GetName來訪問FName
  AEmployee.Free;
end;
(二)操作封裝
unit Unit2;

interface
type
  TDivision=Class
  public
  態性讓你的程式更據有“柔韌性”
  function GetDiv(Num1,Num2:Double):Double;overload;
  function GetDiv(Num1,Num2:integer):integer;overload;
  end;
implementation

{ Division }

function TDivision.GetDiv(Num1, Num2: Double): Double;
begin
  try
  Result:=Num1/Num2;
  except
  Result:=0;//提供彈形處理機制,處理除數為0情況
  end;
end;

function TDivision.GetDiv(Num1, Num2: integer): integer;
begin
  try
  Result:=Num1 div Num2;
  except
  Result:=0;//提供彈形處理機制,處理除數為0情況
  end;
end;

end.
如上程式碼我們透過類的多型性機制把除法分別處理成整除和非整除,又透過異常處理屏
去除數為0的情況,從而保證操作的安全性,在時,我們就可以這樣來:
uses
  unit2;
{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  Division:TDivision;
  IValue:integer;
  FValue:Double;
begin
  Division:=TDivision.Create;
  IValue:=Division.GetDiv(1,2);
  FValue:=Division.GetDiv(1.0,2);
  IValue:=Division.GetDiv(1,0);
  FValue:=Division.GetDiv(1.0,0);
  Division.Free;
end;
 
6.類是一種程式碼重用機制
  比方在5中我們想對這個類加上一個GetAdd函式來作加法運算就可以用類的繼承。如
下寫就可以了:
(一)
unit Unit2;

interface
type
  TDivision=Class
  public
  function GetDiv(Num1,Num2:Double):Double;overload;
  function GetDiv(Num1,Num2:integer):integer;overload;
  end;
type
  TOperation=Class(TDivision)
  public
  function GetAdd(Num1,Num2:Double):Double;
  end;
implementation

{ Division }

function TDivision.GetDiv(Num1, Num2: Double): Double;
begin
  try
  Result:=Num1/Num2;
  except
  Result:=0;
  end;
end;

function TDivision.GetDiv(Num1, Num2: integer): integer;
begin
  try
  Result:=Num1 div Num2;
  except
  Result:=0;
  end;
end;

{ TOperation }

function TOperation.GetAdd(Num1, Num2: Double): Double;
begin
  Result:=Num1+Num2;
end;

end.
這裡我們從TDivision繼承了一個子類TOperation。TOperation就可以即有TDivsion
公有方法GetDiv,又有自己的獨特的方法GetAdd。這是類為我們提供的“魚和熊掌兼
得”之法。不錯吧。:)


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

相關文章