經過實測,Delphi 2007 確支援堆疊物件——這讓我相當興奮。自 Delphi 誕生以來,僅允許繼承 TObject 的堆積物件,必須透過 Create/Free 建構與銷毀,無法使用堆疊物件。堆疊物件優勢在於定義便利、自動呼叫建構/解構函式、離開作用域自動清理,若 Delphi 完整支援將是開發者福音。
但進一步測試令人失望,請看程式碼:
type
TMyRecord = record
private
x: Integer;
y: Integer;
public
// error: Parameterless constructors not allowed record types
// constructor Create;
// error: A record cannot introduce a destructor
// destructor TMyRecird;
constructor Create(a: Integer);
constructor TMyRecord; overload;
constructor TMyRecord(a, b: Integer); overload;
procedure Display;
property xi: Integer read x;
end;
constructor TMyRecord.Create(a: Integer);
begin
x := a; y := 0;
end;
procedure TMyRecord.Display;
begin
ShowMessage(Format('x = %d, y = %d', [x, y]));
end;
constructor TMyRecord.TMyRecord;
begin
x := 0; y := 0;
end;
constructor TMyRecord.TMyRecord(a, b: Integer);
begin
x := a; y := b;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
rec: TMyRecord;
begin
rec.TMyRecord(100, 200);
rec.Display;
end;
可見確可像 C++ 一樣定義區域 record 物件(無需動態建立),並能呼叫方法與屬性。查看 Button1Click 的組合語言碼(CPU 除錯視窗):
Unit1.pas.72: begin 0045ACDC 83C4F8 add esp,-$08 Unit1.pas.73: rec.TMyRecord(100, 200); 0045ACDF 8BC4 mov eax,esp 0045ACE1 B9C8000000 mov ecx,$000000c8 0045ACE6 BA64000000 mov edx,$00000064 0045ACEB E8E4FFFFFF call TMyRecord.TMyRecord Unit1.pas.74: rec.Display; 0045ACF0 8BC4 mov eax,esp 0045ACF2 E855FFFFFF call TMyRecord.Display Unit1.pas.75: end; 0045ACF7 59 pop ecx 0045ACF8 5A pop edx 0045ACF9 C3 ret
組合語言顯示 rec 確為標準 C++ 風格堆疊物件,呼叫方法時隱含傳遞 Self 指標(mov eax,esp),區別於一般 record 變數,是實實在在的「物件」變數。
遺憾的是:
destructor 方法TObject 預設的無參數 Create,帶參數可行),但定義時**不會自動呼叫**建構函式(原以為同名建構函式如 C++ 般自動調用)record 再呼叫靜態程序無異,堆疊物件主要優勢盡失技術上編譯器只需在堆疊配置/釋放記憶體時隱含呼叫建構/解構函式即可,難度不大。雖感遺憾,但仍為這點進步高興——至少可利用此功能封裝 record,且無需擔心物件本身銷毀問題(record 內動態配置記憶體仍需手動釋放)。
object 關鍵字網友 housisong 指出,Delphi 早已支援用 object 關鍵字定義堆疊物件(Delphi 7 即可用),且比 2007 的 record 更完善:record 不可繼承,object 可繼承。原來我孤陋寡聞了!