在 pil 中,lua 的作者推薦了一種方案來實現 OO,比較簡潔,但是我依然覺得有些繁瑣。
這里給出一種更漂亮一點的解決方案,見下文:
這里提供 Lua 中實現 OO 的一種方案:
復制代碼 代碼如下:
local _class={}
function class(super)
local class_type={}
class_type.ctor=false
class_type.super=super
class_type.new=function(...)
local obj={}
do
local create
create = function(c,...)
if c.super then
create(c.super,...)
end
if c.ctor then
c.ctor(obj,...)
end
end
create(class_type,...)
end
setmetatable(obj,{ __index=_class[class_type] })
return obj
end
local vtbl={}
_class[class_type]=vtbl
setmetatable(class_type,{__newindex=
function(t,k,v)
vtbl[k]=v
end
})
if super then
setmetatable(vtbl,{__index=
function(t,k)
local ret=_class[super][k]
vtbl[k]=ret
return ret
end
})
end
return class_type
end
現在,我們來看看怎么使用:
base_type=class() -- 定義一個基類 base_type
復制代碼 代碼如下:
function base_type:ctor(x) -- 定義 base_type 的構造函數
print("base_type ctor")
self.x=x
end
function base_type:print_x() -- 定義一個成員函數 base_type:print_x
print(self.x)
end
function base_type:hello() -- 定義另一個成員函數 base_type:hello
print("hello base_type")
end
以上是基本的 class 定義的語法,完全兼容 lua 的編程習慣。我增加了一個叫做 ctor 的詞,作為構造函數的名字。
下面看看怎樣繼承:
復制代碼 代碼如下:
test=class(base_type) -- 定義一個類 test 繼承于 base_type
function test:ctor() -- 定義 test 的構造函數
print("test ctor")
end
function test:hello() -- 重載 base_type:hello 為 test:hello
print("hello test")
end
現在可以試一下了:
復制代碼 代碼如下:
a=test.new(1) -- 輸出兩行,base_type ctor 和 test ctor 。這個對象被正確的構造了。
a:print_x() -- 輸出 1 ,這個是基類 base_type 中的成員函數。
a:hello() -- 輸出 hello test ,這個函數被重載了。
在這個方案中,只定義了一個函數 class(super) ,用這個函數,我們就可以方便的在 lua 中定義類:
復制代碼 代碼如下:
base_type=class() -- 定義一個基類 base_type
function base_type:ctor(x) -- 定義 base_type 的構造函數
print("base_type ctor")
self.x=x
end
function base_type:print_x() -- 定義一個成員函數 base_type:print_x
print(self.x)
end
function base_type:hello() -- 定義另一個成員函數 base_type:hello
print("hello base_type")
end
以上是基本的 class 定義的語法,完全兼容 lua 的編程習慣。我增加了一個叫做 ctor 的詞,作為構造函數的名字。
下面看看怎樣繼承: test=class(basetype) -- 定義一個類 test 繼承于 basetype
復制代碼 代碼如下:
function test:ctor() -- 定義 test 的構造函數
print("test ctor")
end
function test:hello() -- 重載 base_type:hello 為 test:hello
print("hello test")
end
現在可以試一下了:
復制代碼 代碼如下:
a=test.new(1) -- 輸出兩行,base_type ctor 和 test ctor 。這個對象被正確的構造了。
a:print_x() -- 輸出 1 ,這個是基類 base_type 中的成員函數。
a:hello() -- 輸出 hello test ,這個函數被重載了。
其實,實現多重繼承也并不復雜,這里就不再展開了。更有意義的擴展可能是增加一個 dtor :)
ps. 這里用了點小技巧,將 self 綁定到 closure 上,所以并不使用 a:hello 而是直接用 a.hello 調用成員函數。這個技巧并不非常有用,從效率角度上說,還是不用為好。