最初版は Lua 5.0 に基づいて書かれました。後からのバージョンでも概ね関連していますが、いくつか違いがあります。
第 4 版は 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()
これまでのところ、SpecialAccountAccount のインスタンスに過ぎません。ここで素晴らしいことが起こります
    s = SpecialAccount:new{limit=1000.00}
SpecialAccount は、他のメソッドと同じように Account から new を継承します。しかし、この場合、new が実行されると、self パラメータは SpecialAccount を参照します。したがって、s のメタテーブルは SpecialAccount になり、インデックス __index の値も SpecialAccount になります。つまり、sAccount から継承する SpecialAccount から継承します。次のように評価すると
    s:deposit(100.00)
Lua は sdeposit フィールドがないので 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 は新しい withdraw メソッドを最初に SpecialAccount で見つけるので Account にはアクセスしません。s.limit は 1000.00(s の作成時にこのフィールドを設定したことを思い出してください)であるため、プログラムは引き出しを行い、s は残高をマイナスにします。

Lua の OO の興味深い点は、新しい動作を指定するために新しいクラスを作成する必要がないことです。単一のオブジェクトに特定の動作が必要な場合は、その動作をオブジェクトに直接実装できます。たとえば、アカウント s が常に残高の 10% である金額の引き出しを許可する特別なクライアントの場合は、この単一のアカウントだけを変更できます

    function s:getLimit ()
      return self.balance * 0.10
    end
この宣言後、s:withdraw(200.00) の呼び出しは SpecialAccount から withdraw メソッドを実行しますが、そのメソッドが self:getLimit を呼び出すと、最後に呼び出されるのはこの定義です。