Skip to content

Instantly share code, notes, and snippets.

@akirayu101
Created February 5, 2015 11:31
Show Gist options
  • Save akirayu101/d88f278d5ad2b3aadca7 to your computer and use it in GitHub Desktop.
Save akirayu101/d88f278d5ad2b3aadca7 to your computer and use it in GitHub Desktop.
-- Internal register table
local _class={}
--Create an class(为了不与cocos2d-x中给出的class的名字冲突,这里创建接口改名为luaClass)
function luaClass(base)
local superType = type(base)
local vtbl = {}
local class_type = {}
class_type.ctor = false
class_type.__type = 'class'
class_type.__vtbl = vtbl
--Delegate to vtbl
_class[class_type] = vtbl
setmetatable(class_type,{
__newindex = vtbl,
__index = vtbl,
__call = function(self, ...) return self:new(...) end})
if "class" == superType then
--base is a class
setmetatable(vtbl,{
__index= function(t,k)
local ret=_class[base][k]
vtbl[k]=ret
return ret
end})
class_type.__base = base
--save the top createFunc,this is used to create a object
class_type.__createFunc = base.__createFunc
elseif "function" == superType then
--base is a function, used to create a userdata like cc.Node
class_type.__createFunc = base
elseif nil ~= base then
--base must be a 'class' type or a 'function' type
assert(false)
return nil
end
function class_type:new(...)
local obj = {}
--
--step1,check if are derived from userdata
--
if class_type.__createFunc then
--如果是userdata,也就是从c++中而来,其实需要把method绑定到instance的cObject
local cInstance = class_type.__createFunc()
--相互维持引用(不用担心循环引用是否会导致gc问题,因为不会)
cInstance['.lua_instance'] = obj
obj['.c_instance'] = cInstance
--由userdata获得lua对象
function cInstance:getLuaInstance()
return obj
end
--由lua对象获得userdata
function obj:getCInstance()
return cInstance
end
end
obj.__base = class_type
obj.__type = 'object'
--
--step2,set the __index meta method, thus object can access the class
--
local function lazyIndex(o, key)
if vtbl[key] then
return vtbl[key]
elseif rawget(o, ".c_instance") and o['.c_instance'][key] ~= nil then
rawset(o, key, function(self, ... ) return self:getCInstance()[key](self, ...) end)
return o[key]
else
return nil
end
end
setmetatable(obj,{ __index = lazyIndex})
--
--step3,construct the object
--
do
local create
create = function(c, ...)
if c.__base then
create(c.__base, ...)
end
if c.ctor then
c.ctor(obj, ...)
end
end
create(class_type,...)
end
--
--step4,forbidden the new operation after construction
--
local function forbiddenNewIndex(o, k, v)
--use print but not cclog or not logger, this is to reduce the dependent on other modules
print(string.format("Warning:trying to create '%s' = '%s' in '%s', __newindex shouldnot be accessed outof ctor",
tostring(k), tostring(v), tostring(o)))
rawset(o, k, v)
end
--not need rightnow
--local mt = getmetatable(obj)
--mt.__newindex = forbiddenNewIndex
return obj
end
function class_type:super(f, ...)
assert('object' == self.__type,
string.format("'self' must be a object when call super(self, '%s', ...)", tostring(f)))
local originBase = self.__base
--find the first f function that differ from self[f] in the inheritance chain
local s = originBase
local base = s.__base
while base and s[f] == base[f] do
s = base
base = base.__base
end
assert(base and base[f],
string.format("base class or function cannot be found when call .super(self, '%s', ...)", tostring(f)))
--now base[f] is differ from self[f], but f in base also maybe inherited from base's baseClass
while base.__base and base[f] == base.__base[f] do
base = base.__base
end
-- If the base also has a baseclass, temporarily set :super to call that baseClass' methods
-- this is to avoid stack overflow
if base.__base then
self.__base = base
end
--now, call the super function
local result = base[f](self, ...)
--set back
if base.__base then
self.__base = originBase
end
return result
end
-- 组合一个obj,把没有的接口代理到这个object中, 注意,此obj应该是lua的table
-- 而不是c++的userdata,但是此obj可以是从c++中方法中继承出来的对象
function class_type:compose(object)
assert('object' == self.__type and 'object' == object.__type,
string.format("'self' and 'object' must be a object when call compose(self, object)", tostring(f)))
for k, v in pairs(object.__base.__vtbl) do
-- 先确定是否要进行代理组合下去
if type(v) == "function" then
-- 不是以_开始,公有函数
-- 且在对象本身中没有这种方法
if string.byte(k, 1) ~= 95 and self[k] == nil then
self[k] = function(self, ...) return object[k](object, ...) end
end
end
end
end
return class_type
end
--test code
--[[super = luaClass(function() return cc.Node:create() end)
function super:ctor()
print("super:ctor")
end
function super:show()
print("super:show")
end
child = luaClass(super)
function child:ctor()
print("child:ctor")
end
function child:show()
self:super('show')
print("child:show")
end
local o = child:new()
o:show()
local t1 = os.clock()
for i = 1, 1000000, 1 do
o:setPosition(cc.p(1, 1))
end
local t2 = os.clock()
print(t2 - t1)]]--
--test compose
--[[obj = luaClass()
function obj:ctor()
print("obj:ctor")
end
function obj:show()
print("obj:show")
end
obj2 = luaClass()
function obj2:ctor()
print("obj2:ctor")
end
function obj2:fuck()
print("obj2:fuck")
end
local o = obj:new()
local o2 = obj2:new()
o:compose(o2)
o:fuck()]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment