第一版是為 Lua 5.0 編寫的。雖然對後續版本仍有很大的關聯性,但有些地方有所不同。
第四版針對 Lua 5.3,可在 Amazon 和其他書店購買。
購買這本書,您也協助 支持 Lua 專案。
![]() |
程式設計 in Lua | ![]() |
第二部分。表格和物件 第 16 章。物件導向程式設計 |
由於物件在 Lua 中並非原始型別,因此有許多方法可以在 Lua 中執行物件導向程式設計。我們之前看到的 method,使用索引 metamethod,可能是簡單性、效能和彈性的最佳組合。不過,還有其他實作可能更適合某些特定情況。在這裡,我們將看到一個允許在 Lua 中進行多重繼承的替代實作。
此實作的關鍵是使用函式作為 metafield __index
。請記住,當表格的 metatable 在 __index
欄位中有一個函式時,Lua 會在找不到原始表格中的金鑰時呼叫該函式。然後,__index
可以查詢它想要的任意數量的父類別中的遺失金鑰。
多重繼承表示一個類別可能有多個超類別。因此,我們無法使用類別 method 建立子類別。相反地,我們將定義一個特定函式來執行此目的,createClass
,其參數為新類別的超類別。此函式會建立一個表格來表示新類別,並設定其 metatable,其中包含執行多重繼承的 __index
metamethod。儘管有多重繼承,每個實例仍屬於單一類別,它會在其中尋找其所有 method。因此,類別和超類別之間的關係與類別和實例之間的關係不同。特別是,類別不能同時作為其實例的 metatable 和其自己的 metatable。在以下實作中,我們將類別保留為其實例的 metatable,並建立另一個表格作為類別的 metatable。
-- 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
和另一個類別 Named
,它只有兩個 method,setname
和 getname
Named = {} function Named:getname () return self.name end function Named:setname (n) self.name = n end若要建立一個新的類別
NamedAccount
,它是 Account
和 Named
的子類別,我們只需呼叫 createClass
NamedAccount = createClass(Account, Named)要建立並使用實例,我們照常進行
account = NamedAccount:new{name = "Paul"} print(account:getname()) --> Paul現在讓我們追蹤最後一個陳述式中發生了什麼事。Lua 在
account
中找不到欄位 "getname"
。因此,它會在 account
的元表中尋找 __index
欄位,也就是 NamedAccount
。但 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}) ...使用這個技巧,存取繼承的方法會和存取本機方法一樣快(除了第一次存取)。缺點是,在系統執行後很難變更方法定義,因為這些變更不會傳播到階層鏈中。
版權所有 © 2003–2004 Roberto Ierusalimschy。保留所有權利。 | ![]() |