第一版是針對 Lua 5.0 所寫的。雖然在後續版本中仍然有很大的關聯性,但仍有一些差異。
第四版針對 Lua 5.3,可在 Amazon 和其他書店購買。
購買這本書,您也同時協助 支援 Lua 專案


16.2 – 繼承

由於類別是物件,因此它們也可以從其他類別取得方法。這使得在 Lua 中實作繼承(以通常的物件導向意義)變得相當容易。

假設我們有一個基礎類別,例如 Account

    Account = {balance = 0}
    
    function Account:new (o)
      o = o or {}
      setmetatable(o, self)
      self.__index = self
      return o
    end
    
    function Account:deposit (v)
      self.balance = self.balance + v
    end
    
    function Account:withdraw (v)
      if v > self.balance then error"insufficient funds" end
      self.balance = self.balance - v
    end

從該類別,我們要衍生一個子類別 SpecialAccount,允許客戶提領超過其餘額的金額。我們從一個空類別開始,它僅從其基礎類別繼承所有操作

    SpecialAccount = Account:new()
到目前為止,SpecialAccount 僅是 Account 的一個執行個體。現在發生了美好的事情
    s = SpecialAccount:new{limit=1000.00}
SpecialAccountAccount 繼承 new,就像任何其他方法一樣。然而,這次當 new 執行時,self 參數將參考 SpecialAccount。因此,s 的元表將會是 SpecialAccount,其在索引 __index 的值也是 SpecialAccount。因此,sSpecialAccount 繼承,而 SpecialAccountAccount 繼承。當我們評估
    s:deposit(100.00)
Lua 無法在 s 中找到 deposit 欄位,因此它會尋找 SpecialAccount;它也無法在其中找到 deposit 欄位,因此它會尋找 Account,並在那裡找到存款的原始實作。

SpecialAccount 變得特別的是,它可以重新定義從其超類別繼承的任何方法。我們所要做的就是撰寫新的方法

    function SpecialAccount:withdraw (v)
      if v - self.balance >= self:getLimit() then
        error"insufficient funds"
      end
      self.balance = self.balance - v
    end
    
    function SpecialAccount:getLimit ()
      return self.limit or 0
    end
現在,當我們呼叫 s:withdraw(200.00) 時,Lua 沒有轉到 Account,因為它首先在 SpecialAccount 中找到了新的 withdraw 方法。由於 s.limit 是 1000.00(請記住,我們在建立 s 時設定了這個欄位),所以程式執行了提款,讓 s 變成負餘額。

Lua 中物件導向的一個有趣面向是,您不需要建立一個新類別來指定一個新的行為。如果只有一個物件需要一個特定的行為,您可以直接在物件中實作它。例如,如果帳戶 s 代表某個特殊客戶,她的額度總是餘額的 10%,您可以只修改這個單一帳戶

    function s:getLimit ()
      return self.balance * 0.10
    end
在那個宣告之後,呼叫 s:withdraw(200.00) 執行了 SpecialAccount 中的 withdraw 方法,但是當那個方法呼叫 self:getLimit 時,它呼叫的是這個最後的定義。