Created
February 5, 2015 11:31
-
-
Save akirayu101/d88f278d5ad2b3aadca7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- 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