この初版は Lua 5.0 用に書かれました。より新しいバージョンでも依然として大まかに関連がありますが、いくつかの相違があります。
第 4 版は Lua 5.3 を対象としたもので、Amazon およびその他の書店で入手できます。
この書籍を購入することで、Lua プロジェクトをサポートできます。
![]() |
プログラミング inLua | ![]() |
パート II. テーブルとオブジェクト 第 16 章. オブジェクト指向プログラミング |
Lua ではオブジェクトがプリミティブではないため、Lua でオブジェクト指向プログラミングを行う方法はいくつかあります。インデックスメタメソッドを使用した私たちが以前に見た方法は、おそらく簡潔性、パフォーマンス、柔軟性の最高の組み合わせです。それにも関わらず、特定のケースにさらに適している可能性のある他の実装があります。ここでは Lua で多重継承を可能にする代替の実装を見ていきます。
この実装の鍵は、メタフィールド __index
に関数をで使用することです。テーブルのメタテーブルの __index
フィールドに関数がある場合は、元のテーブルでキーが見つからない場合に常に Lua がその関数を呼び出すことを覚えておいてください。その後、__index
は、必要な数の親で欠落しているキーを検索できます。
多重継承とは、クラスが複数のスーパークラスを持つ可能性があることを意味します。そのため、クラスメソッドを使用してサブクラスを作成することはできません。その代わり、その目的に特化した関数 createClass
を定義します。この関数は、新しいクラスのスーパークラスを議論として持ちます。この関数は、新しいクラスを表すテーブルを作成し、多重継承を行う __index
メタメソッドを使用してメタテーブルを設定します。多重継承にもかかわらず、各インスタンスは 1 つのクラスに属し、それらすべてのメソッドを探します。したがって、クラスとスーパークラスの間の関係は、クラスとインスタンスの間の関係とは異なります。特に、クラスはインスタンスのメタテーブルとそれ自身のメタテーブルの両方を同時に持つことはできません。この実装では、インスタンスのメタテーブルとしてクラスを保持し、クラスのメタテーブルとなる別のテーブルを作成します。
-- look up for `k' in list of tables `plist' local function search (k, plist) for i=1, table.getn(plist) do local v = plist[i][k] -- try `i'-th superclass if v then return v end end end function createClass (...) local c = {} -- new class -- class will search for each method in the list of its -- parents (`arg' is the list of parents) setmetatable(c, {__index = function (t, k) return search(k, arg) end}) -- prepare `c' to be the metatable of its instances c.__index = c -- define a new constructor for this new class function c:new (o) o = o or {} setmetatable(o, c) return o end -- return new class return c end
小さい例を使用して createClass
の使用について説明しましょう。以前の Account
クラスと、setname
と getname
という 2 つのメソッドのみを持つ、Named
という別のクラスがあると仮定します。
Named = {} function Named:getname () return self.name end function Named:setname (n) self.name = n end
Account
と Named
の両方のサブクラスである新しいクラス NamedAccount
を作成するには、createClass
を呼び出すだけです。NamedAccount = createClass(Account, Named)インスタンスを作成して使用する方法は通常どおりです。
account = NamedAccount:new{name = "Paul"} print(account:getname()) --> Paul最後のステートメントで何が起こるかを見てみましょう。Lua は
account
でフィールド getname
を見つけることができません。そこで、account
のメタテーブル、つまり NamedAccount
の __index
フィールドを探します。しかし、NamedAccount
も getname
フィールドを提供できないため、Lua は NamedAccount
のメタテーブルの __index
フィールドを探します。このフィールドには関数が含まれているため、Lua はそれを呼び出します。この関数は最初に Account
で getname
を検索しますが、見つからず、次に Named
で検索します。ここで非 nil の値が見つかり、検索の最終結果となります。もちろん、この検索の根本的な複雑さにより、多重継承のパフォーマンスは単一継承と同じではありません。このパフォーマンスを向上させる簡単な方法は、継承したメソッドをサブクラスにコピーすることです。この手法を使用すると、クラスのインデックスメタメソッドは次のように記述できます。
... setmetatable(c, {__index = function (t, k) local v = search(k, arg) t[k] = v -- save for next access return v end}) ...このテクニックにより、継承されたメソッドへのアクセスはローカルメソッドへのアクセスと同じくらい高速になります(最初のアクセスを除く)。欠点は、システム実行後にメソッド定義を変更するのが難しいことです。これらの変更は階層チェーンのどこにも伝播しないためです。
Copyright © 2003–2004 Roberto Ierusalimschy. All rights reserved. | ![]() |