方法是類行為的載體,Delphi 提供豐富的方法修飾符構建多態、封裝、元編程能力。本文系統講解虛/動態方法差異、覆蓋與重定義規則、實現時參數省略、訪問限制、靜態/類/靜態類方法、方法重載、inherited 語義、抽象方法/類、final/sealed、構造/析構方法、事件方法、消息方法、調用約定等完整知識體系。
| 維度 | 虛方法 (virtual) | 動態方法 (dynamic) |
|---|---|---|
| 查找表 | VMT (虛方法表),含所有祖先虛方法 | DMT (動態方法表),僅含當前類動態方法 |
| 調用速度 | 快 (單次間接索引) | 較慢 (可能需沿繼承鏈查找 DMT) |
| 內存佔用 | 大 (每類一個完整 VMT) | 小 (僅存儲自有動態方法) |
| 歷史 | Delphi 1 即有 | 後期引入以節省 VCL 體積 |
| 事件方法 | 早期定義 | VCL 事件多為 dynamic |
| 互換性 | 可相互替換 | 可相互替換 |
建議:高頻調用、核心多態用 virtual;事件、低頻、大量類層級用 dynamic。
{標準覆蓋}
TBass = class procedure Proc; virtual; end;
TChild = class(TBass) procedure Proc; override; end;
{重定義情況 (編譯警告)}
1. 父無 virtual, 子無 override
2. 父無 virtual, 子 virtual
3. 父 virtual, 子 virtual (無 override)
4. 父 virtual, 子無關鍵字
5. 父 virtual, 子 dynamic
{消除警告}
- 子方法加 reintroduce
- 或 {$WARNINGS OFF} ... {$WARNINGS ON}
TBass = class
function Fun1(x,y: Integer): Integer; virtual;
function Fun2(x,y,z: Integer): Integer;
end;
function TBass.Fun1(x,y: Integer): Integer; {實現不可帶 virtual}
function TBass.Fun2; {僅寫函數名, 參數/返回類型自動繼承}
| 區域 | 關鍵字 | 可訪問範圍 | RTTI |
|---|---|---|---|
| 公共 (默認) | - | 單元外可見 | {$M+} 時屬 published |
| 私有 | private | 僅類內部 | 無 |
| 保護 | protected | 類內部 + 子孫類 | 無 |
| 公開 | public | 完全公開 | 無 |
| 發布 | published | 公開 + RTTI + 設計時 | 有 |
| 嚴格私有 | strict private | 僅類內部 (單元外不可見) | 無 |
| 嚴格保護 | strict protected | 類內部 + 子孫類 (單元外不可見) | 無 |
同一單元內類互為「友元」,可訪問私有/保護成員(除非用 strict)。
virtual/dynamic/class,需實例調用。class procedure/class function,可通過類名直接調用 (TMyClass.Alert('Hi')),不可訪問實例字段,不可為虛方法。class procedure ... static;,可放 private,用於類屬性讀寫,不佔用 VMT/DMT。overload。overload。published 區禁止重載(編譯器會自動將公共區重載移至 public)。procedure TChild.Proc;
begin
inherited Proc; {調用父類同名方法, 可省略方法名}
inherited; {完全等價}
inherited Proc(1,2); {傳遞參數}
ShowMessage(inherited Fun(11,22)); {調用父類函數並用返回值}
end;
TMyClass = class
procedure Proc1; virtual; abstract; {純虛方法}
function Fun: string; dynamic; abstract;
end;
{現代語法}
TBass = class abstract(TObject)
procedure Proc; virtual; abstract;
end;
TStrings 是經典抽象類,實例化需用 TStringList。
TB = class(TA)
procedure Proc; override; final; {不可再被覆蓋}
end;
TMyClass = class sealed(TObject) {不可被繼承}
end;
constructor Create; {可重載, 編譯器自動處理 inherited Create}
destructor Destroy; override; {虛方法, 配合 Free 安全釋放}
constructor TMyClass.Create(x,y: Integer);
begin
inherited; {調用父類 Create}
{初始化}
end;
destructor TMyClass.Destroy;
begin
{清理}
inherited; {調用父類 Destroy}
end;
事件本質是方法指針類型屬性,屬性讀寫對應 add/remove 訪問器,IDE 雙擊自動生成骨架。
procedure KeyDown(var Msg: TWMKeyDown); message WM_KEYDOWN;
{參數必須 var, 類型為對應消息記錄}
{消息攔截優先於事件, inherited 可轉發給父類/事件}
| 指示字 | 參數順序 | 棧清理 | 參數傳遞 | 用途 |
|---|---|---|---|---|
| register | 左→右 | 被調用者 | 前 3 參數用寄存器 | Delphi 默認,最快 |
| pascal | 左→右 | 被調用者 | 棧 | 兼容 Pascal |
| cdecl | 右→左 | 調用者 | 棧 | C/C++ DLL、非 Windows |
| stdcall | 右→左 | 被調用者 | 棧 | Windows API |
| safecall | 右→左 | 被調用者 | 棧 | COM 雙重介面 |
Delphi 方法體系極其完備,從虛/動態多態到類/靜態類元編程,從消息攔截到底層調用約定,精準掌握各修飾符語義與組合規則,是編寫高性能、可擴展、互操作類庫的關鍵。