Delphi 建立在 Object Pascal 之上,完整支援封裝、繼承、多型。許多開發者僅停留在「拖拉元件」的 RAD 模式,錯失了 OOP 帶來的架構彈性。本文系統講解三大支柱觀念、類別與物件關係、建構子/解構子、虛擬/抽象方法、介面與實作分離,並揭示 VCL 龐大繼承鏈 (TObject → TForm) 如何運用這些機制。
1. 類別與物件:型別 vs 實例
type
TDate = class
Month, Day, Year: Integer;
procedure SetValue(M, D, Y: Integer);
function LeapYear: Boolean;
end;
var
ADay: TDate; // 變數宣告 (參考型別)
begin
ADay := TDate.Create; // 建構子建立實例,配置記憶體
ADay.SetValue(1, 1, 2000);
if ADay.LeapYear then ShowMessage('閏年');
ADay.Free; // 解構子釋放記憶體
end;
- 類別:用戶定義的資料型別,包含欄位 (資料) 與方法 (行為)。
- 物件:類別的實例,擁有獨立記憶體空間。
- Delphi 採「參考模型」:變數存放指標,
Create 配置記憶體並回傳指標,Free 釋放。未 Create 直接存取 → Access Violation (常見錯誤訊息 Read of Address: FFFFFFFF)。
2. 封裝:存取層級控制
| 關鍵字 | 可見範圍 |
private | 同單元內 (Delphi 特有:同 .pas 檔皆可見,較標準 OOP 寬鬆) |
protected | 同單元 + 衍生類別 |
public | 任何引用該單元的程式碼 |
published | public + RTTI (設計期屬性編輯器可見) |
最佳實踐:欄位置 private,對外暴露 property (配合 read/write 方法),內部邏輯置 protected 供衍生類別擴充。
3. 繼承與衍生:重用與擴充
type
TNewDate = class(TDate) // 繼承 TDate
public
function GetTextNew: String; // 新增方法
end;
- 衍生類別自動擁有基類所有非私有成員 (Delphi
private 同單元可見,故同單元衍生類別仍可存取基類 private)。
- 若需真正隱藏基類欄位供衍生類別存取,需置
protected。
- 衍生類別可新增欄位/方法、覆寫虛擬方法、實作抽象方法。
4. 建構子與解構子
- 所有類別隱含繼承
TObject,故皆有 Create (Constructor) 與 Destroy (Destructor)。
Free = if Self <> nil then Destroy,較安全,建議統一用 Free。
- 建構子可多載 (overload) 接受參數,完成初始化:
constructor Create(M, D, Y: Integer); → ADay := TDate.Create(1,1,2000);
5. 虛擬方法、覆寫與多型
type
TAnimal = class
procedure Voice; virtual; // 虛擬方法
end;
TDog = class(TAnimal)
procedure Voice; override; // 覆寫
end;
procedure TDog.Voice;
begin
inherited; // 呼叫基類版本 (可選)
PlaySound('Dog.wav', 0, SND_ASYNC);
end;
virtual:允許衍生類別 override。
override:提供新實作,執行時依物件實際型別決定呼叫哪個版本 (動態綁定)。
inherited:在覆寫方法中呼叫基類同名虛擬方法程式碼。
6. 抽象方法與介面契約
type
TShape = class
procedure Draw; virtual; abstract; // 純虛擬/抽象方法
end;
TCircle = class(TShape)
procedure Draw; override; // 必須實作
end;
- 抽象方法只有宣告無實作,直接呼叫會拋出
EAbstractError。
- 含抽象方法的類別為抽象類別,**不可建立實例** (C++ 限制較嚴格,Delphi 允許建立但呼叫會出錯)。
- 目的:定義介面契約,強制衍生類別實作特定行為。
7. 多型:同一介面、不同行為
var
A1, A2: TAnimal;
begin
A1 := TAnimal.Create;
A2 := TDog.Create; // 子類別指標指派給父類別變數:合法
A1.Voice; // 播放 Animal.wav
A2.Voice; // 播放 Dog.wav (多型:同一呼叫,不同實作)
A1.Free; A2.Free;
end;
- 指派相容性:子類別實例可指派給父類別變數 (向上轉型);反向需硬性轉型且風險自負。
- 多型威力:程式碼針對抽象基類 (或介面) 設計,自動支援所有現有與未來的衍生類別,無需修改既有程式碼 (開放/封閉原則)。
8. VCL 繼承鏈實例
TObject
→ TPersistent (指派/串流)
→ TComponent (擁有權/設計期)
→ TControl (視覺/座標)
→ TWinControl (視窗控制項/HWND)
→ TScrollingWinControl (捲軸)
→ TCustomForm (表單基礎)
→ TForm (設計期表單)
每層僅新增/覆寫該層級職責,TForm 開發者只需關注業務邏輯,視窗建立、訊息迴圈、最大化/最小化、焦點管理等底層細節皆由祖先類別封裝完成。
9. 介面與實作分離
type
ISample = interface
function GetString: String;
end;
TSample = class(TInterfacedObject, ISample)
function GetString: String;
end;
var
Intf: ISample;
begin
Intf := TSample.Create; // 介面參考計數自動管理生命週期
ShowMessage(Intf.GetString);
Intf := nil; // 釋放 (不需手動 Free)
end;
- 介面無資料欄位、無
private/protected、方法預設 public。
TInterfacedObject 實作 IInterface (參考計數 _AddRef/_Release),支援介面自動釋放。
- 一個類別可實作多個介面,支援「鴨子型別」多型。
結語
OOP 不是理論裝飾,而是管理複雜度的工具。Delphi 開發者若能熟練運用「封裝隱藏細節、繼承重用邏輯、多型統一介面、介面解耦實作」,配合 VCL 既有架構,即可從「表單設計師」進化為「系統架構師」。建議進階閱讀:Design Patterns (GoF)、Delphi Design Patterns、原始碼 Classes.pas, Controls.pas。
- 上一篇文章: Delphi 控制項 Handle 建立時機:在 CreateWnd 覆寫中執行後續初始化
- 下一篇文章: Delphi 開發實用技巧大全:檔案操作、註冊表、多媒體、網路、字串、資料庫、系統資訊 100+ 範例
Copyright ©
程式碼之家 All Rights Reserved