Lua本身是不支持面向對象的,但是可以利用table和元表、元方法進行面向對象的模擬!
以下是Cocos2d-lua中面向對象的實現!
class
function class(classname, ...)
local cls = {__cname = classname}
local supers = {...}
for _, super in ipairs(supers) do
local superType = type(super)
-- 基類的類型只能是table或者function(若爲nil,則無基類),其他類型是無效的
assert(superType == "nil" or superType == "table" or superType == "function",
string.format("class() - create class \"%s\" with invalid super class type \"%s\"",
classname, superType))
if superType == "function" then
assert(cls.__create == nil,
string.format("class() - create class \"%s\" with more than one creating function",
classname));
-- if super is function, set it to __create
cls.__create = super
elseif superType == "table" then
if super[".isclass"] then
-- super is native class
assert(cls.__create == nil,
string.format("class() - create class \"%s\" with more than one creating function or native class",
classname));
cls.__create = function() return super:create() end
else
-- super is pure lua class
cls.__supers = cls.__supers or {}
cls.__supers[#cls.__supers + 1] = super
if not cls.super then
-- set first super pure lua class as class.super
cls.super = super
end
end
else
error(string.format("class() - create class \"%s\" with invalid super type",
classname), 0)
end
end
cls.__index = cls -- cls作爲元表的時候,索引爲自身
if not cls.__supers or #cls.__supers == 1 then -- 沒有或者只有一個基類
setmetatable(cls, {__index = cls.super})
else -- 有多個基類
setmetatable(cls, {__index = function(_, key)
local supers = cls.__supers
for i = 1, #supers do
local super = supers[i]
if super[key] then return super[key] end
end
end})
end
if not cls.ctor then
-- add default constructor
cls.ctor = function() end
end
cls.new = function(...)
local instance
if cls.__create then
instance = cls.__create(...)
else
instance = {}
end
setmetatableindex(instance, cls) -- setmetatableindex見附錄
instance.class = cls
instance:ctor(...)
return instance
end
cls.create = function(_, ...)
return cls.new(...)
end
return cls
end
Test Demo
基類:BaseClass.lua
local BaseClass = class("BaseClass")
function BaseClass:ctor()
print("BaseClass:ctor")
end
function BaseClass:printFunc()
print("this is BaseClass`s printFunc")
end
function BaseClass:testFunc()
print("this is BaseClass`s testFunc")
end
return BaseClass
派生類:DerivativeClass.lua
local baseClass = require("BaseClass"):create()
local DerivativeClass = class("DerivativeClass", baseClass)
function DerivativeClass:ctor()
print("DerivativeClass:ctor")
end
function DerivativeClass:printFunc()
print("this is DerivativeClass`s printFunc")
end
return DerivativeClass
test:
local baseClass = require("BaseClass"):create() -- 調用基類的默認構造函數ctor
baseClass:printFunc() -- 調用基類的printFunc函數
local derivativeClass = require("DerivativeClass"):create() -- 依次調用基類和派生類的默認構造函數
derivativeClass:printFunc() -- 調用派生類的printFunc函數(重寫基類的printFunc函數)
derivativeClass:testFunc() -- 調用基類的testFunc函數
--[[
BaseClass:ctor
this is BaseClass`s printFunc
BaseClass:ctor
DerivativeClass:ctor
this is DerivativeClass`s printFunc
this is BaseClass`s testFunc
]]
附錄
local setmetatableindex_
setmetatableindex_ = function(t, index)
if type(t) == "userdata" then
local peer = tolua.getpeer(t)
if not peer then
peer = {}
tolua.setpeer(t, peer)
end
setmetatableindex_(peer, index)
else
local mt = getmetatable(t)
if not mt then mt = {} end
if not mt.__index then
mt.__index = index
setmetatable(t, mt)
elseif mt.__index ~= index then
setmetatableindex_(mt, index)
end
end
end
setmetatableindex = setmetatableindex_
Just Mark!