is 與 as 總結

Pascal/FPC is 型別判斷、as 安全轉型、TClass(X) 裸強制轉換

is 與 as 的使用方式

1 is 運算子:執行期型別偵測

判斷物件實體是否屬於指定類別或其子類別,回傳布林值 True/False,做為安全前置檢核使用。

2 as 運算子:安全型別轉換

以執行期型別驗證為基礎的向上/向下轉型;若型別不相符則直接拋出例外,優先保障執行安全。

3 TMyClass(X) 裸強制轉換(未檢核轉型)

不執行執行期檢核,直接強制重新解讀記憶體;執行速度更快,但當型別不匹配時會產生未定義行為(程式崩潰、呼叫錯誤方法、記憶體錯誤),僅可在透過 is 確認型別後使用。

program Demo;
{$ifdef FPC} {$mode objfpc}{$H+}{$J-} {$endif}
{$ifdef MSWINDOWS} {$apptype CONSOLE} {$endif}
{$codepage utf8}
uses
  SysUtils;

type
  // 基礎類別
  TFather = class
    procedure FatherMethod;
  end;

  // 衍生類別,繼承 TFather
  TSon = class(TFather)
    procedure SonMethod;
  end;

procedure TFather.FatherMethod;
begin
  WriteLn('FatherMethod');
end;

procedure TSon.SonMethod;
begin
  WriteLn('SonMethod');
end;

var
  Son: TSon;
  C: TFather; // 基礎類別參考變數
begin
  Son := TSon.Create;
  try
    // 衍生類別實體可直接呼叫所有方法
    Son.FatherMethod;
    Son.SonMethod;

    // 向上轉型:將衍生類別指派給基礎類別參考,語法合法
    C := Son;
    C.FatherMethod; // 基礎類別參考可呼叫自身擁有的方法

    // C.SonMethod; // 編譯錯誤:TFather 不存在此方法

    // 1. is 型別判斷 + as 安全轉換
    if C is TSon then
      (C as TSon).SonMethod;

  finally
    FreeAndNil(Son);
  end;
end.Code language: JavaScript (javascript)

執行結果

FatherMethod
SonMethod
FatherMethod
SonMethod

C 原本是 TFather 型別的參考變數 C: TFather;,但實際指向的物件為 C := Son;,子類別實體可透過該參考呼叫父類別方法 C.FatherMethod;

若要呼叫子類別專屬方法 (C as TSon).SonMethod; ,必須先透過 is 進行型別判斷 if C is TSon then,避免執行時發生錯誤。

asTFather(X) 轉換方式對照

1. X as TFather

安全轉型,建議一般場景使用

  • 底層自動執行執行期型別檢核,等同隱式先行執行 X is TMyClass
  • 型別不匹配時拋出 EInvalidCast 例外,程式可攔截處理錯誤;
  • 會產生輕微效能開銷,多數業務程式可忽略不計。

2. TFather(X) 強制裸轉換

無檢核直接轉型,僅適用高效能需求場景,暴力強制轉換記憶體解讀。

  • 完全跳過執行期型別檢查,直接強制解讀物件指標;
  • 執行速度略快;
  • 風險:若 X 實體並非目標類別,呼叫方法會造成記憶體越界、堆疊崩潰、隨機例外(未定義行為);
  • 僅允許搭配前置 is 判斷後使用,確保型別一定相符:
// 安全寫法1:as 轉換(通用)
if A is TFather then
  (A as  TFather).CallSomeMethodOfFather;

// 安全寫法2:裸強制轉換(極致效能,已前置is檢核)
if A is TFather then
  TMyClass(A).CallSomeMethodOfMyClass;Code language: JavaScript (javascript)

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *