lua中没有类的概念,有的只是表(table),而类之间的继承也就是将父类的表连到了一块儿,派生类中没有找到的属性和方法就经过元表查找父类,在cocos2d-lua中,封装好的class方法,完美的实现了类的继承,包括单继承,和多继承,class的源码以下(省去了一些没必要要的代码):数组
1 _setmetatableindex = function(t, index) 2 if type(t) == "userdata" then 3 local peer = tolua.getpeer(t) 4 if not peer then 5 peer = {} 6 tolua.setpeer(t, peer) 7 end 8 _setmetatableindex(peer, index) 9 else 10 local mt = getmetatable(t) 11 if not mt then mt = {} end 12 if not mt.__index then 13 mt.__index = index 14 setmetatable(t, mt) 15 elseif mt.__index ~= index then 16 _setmetatableindex(mt, index) 17 end 18 end 19 end 20 21 22 function class(classname, ...) --参数一:所要建立的类名,参数二:可选参数,能够使function,也能够是table,userdata等 23 local cls = {__cname = classname} 24 25 local supers = {...} 26 for _, super in ipairs(supers) do --遍历可选参数 27 local superType = type(super) 28 if superType == "function" then 29 --若是是个function,那么就让cls的create方法指向他 30 cls.__create = super 31 elseif superType == "table" then --若是是个table 32 if super[".isclass"] then--若是是个原生cocos类,好比cc.Sprite,不是自定义的 33 cls.__create = function() return super:create() end 34 else 35 -- 若是是个纯lua类,本身定义的那种,好比a={} 36 cls.__supers = cls.__supers or {} 37 cls.__supers[#cls.__supers + 1] = super--不断加到__supers的数组中 38 if not cls.super then 39 -- 把第一个遍历到的table做为cls的超类 40 cls.super = super 41 end 42 end 43 44 end 45 end 46 47 cls.__index = cls--不知道做用 48 if not cls.__supers or #cls.__supers == 1 then --这个就是单继承,设置cls的元表的index为他的第一个超类 49 setmetatable(cls, {__index = cls.super}) 50 else 51 setmetatable(cls, {__index = function(_, key)--羡慕是多继承,index指向一个函数,到时候找元素的时候会遍历函数 52 local supers = cls.__supers 53 for i = 1, #supers do 54 local super = supers[i] 55 if super[key] then return super[key] end 56 end 57 end}) 58 end 59 60 if not cls.ctor then 61 -- 增长一个默认构造函数 62 cls.ctor = function() end 63 end 64 cls.new = function(...) --新建方法,这个也是比较重要的方法 65 local instance 66 if cls.__create then 67 --若是有create方法,那么就调用,正常状况下,自定义的cls是没有create方法的。 68 --会不断的向上寻找元类的index,直到找到原生cocos类,好比sprite,而后调用sprite:create() 69 --返回一个原生对象,经过调试代码,能够得出这些 70 71 instance = cls.__create(...) 72 else 73 instance = {}--没有,说明根目录不是cocos类,而是普通类 74 end 75 --这个方法也比较关键,设置instance的元类index,谁调用new了,就把他设置为instance的元类index 76 --具体能够看代码 77 _setmetatableindex(instance, cls) 78 instance.class = cls 79 instance:ctor(...)--调用构造函数 80 return instance 81 end 82 cls.create = function(_, ...) 83 return cls.new(...) 84 end 85 86 return cls 87 end
经过以上方法,能够实现类的继承,那么如何调用这个方法呢,看下面的事例函数
为了说明事例,我又精简了上面的代码,便于咱们说明学习
local _setmetatableindex _setmetatableindex2 = function(t, index) -- print("老是Sprite=" .. t.type ) local mt = getmetatable(t) if not mt then mt = {} print("第一个分支") end if not mt.__index then mt.__index = index setmetatable(t, mt) print("第二个分支") elseif mt.__index ~= index then print("第三个分支") _setmetatableindex2(mt, index) end end function class2(classname, ...) local cls = {__cname = classname} local supers = {...} for _, super in ipairs(supers) do local superType = type(super) if superType == "function" then cls.__create = super elseif superType == "table" then if super[".isclass"] then cls.__create = function() return super:create() end print("走上面") else print("走下面") cls.__supers = cls.__supers or {} cls.__supers[#cls.__supers + 1] = super if not cls.super then cls.super = super end end end end cls.__index = cls if not cls.__supers or #cls.__supers == 1 then setmetatable(cls, {__index = cls.super}) end cls.new = function(...) print("走一遍") local instance if cls.__create then instance = cls.__create(...) print("有函数") else instance = {} print("无函数") end _setmetatableindex2(instance, cls) instance.class = cls return instance end cls.create = function(_, ...) return cls.new(...) end return cls end
调用:字体
--第一个类,这里模仿cocos的Sptite类
local Sprite={} Sprite.type="Sprite" Sprite.wenqian1=111 Sprite[".isclass"]=true function Sprite:create(o) o=o or {} setmetatable(o,self) ; self.__index=self; return o end
--第二个类,这里他继承了Sprite类 GameSprite = class2("GameSprite", -- function() return Sprite:create() end Sprite ) GameSprite.wenqian2=222 --第三个类,这里继承了 GameSprite类 testClass=class2("testClass", -- function() -- return GameSprite:create() -- end GameSprite--,GameSprite2 ) testClass.wenqian3=333 --实例化一个testClass类的对象 local test=testClass:new()
print(test.wenqian1);
print(test.wenqian2)
print(test.wenqian3)lua
运行结果以下:spa
[LUA-print] 走上面
[LUA-print] 走下面
[LUA-print] 走一遍
[LUA-print] 有函数
[LUA-print] 第三个分支
[LUA-print] 第一个分支
[LUA-print] 第二个分支
[LUA-print] 111
[LUA-print] 222
[LUA-print] 333调试
经过class里面的代码,能够看出 返回的local test 实际上就是最顶层的Sprite 类的一个新建对象,而后他的元类的index为testClass,code
而testClass的元类的index为GameSprite,从而wenqian1,wenqian2,wenqian3都可以正确的找到。对象
下面说一下错误的状况,以前因为学习lua比较仓促,没有细看class的原理,因此用了下面的错误方法调用local Sprite={}blog
Sprite.type="Sprite" Sprite.wenqian1=111 Sprite[".isclass"]=true function Sprite:create(o) o=o or {} setmetatable(o,self) ; self.__index=self; return o end GameSprite = class2("GameSprite", -- function() return Sprite:create() end Sprite ) GameSprite.wenqian2=222 testClass=class2("testClass", function() return GameSprite:create() end ) testClass.wenqian3=333 local test=testClass:new() --print( getmetatable(test).__index==GameSprite) --print( getmetatable(getmetatable(test)).__index==testClass) print(test.wenqian1); print(test.wenqian2) print(test.wenqian3)
改动的地方就是红色字体部分,之前第二个参数是GameSprite类,如今成了一个返回GameSprite:create方法,运行结果以下:
[LUA-print] 走上面
[LUA-print] 走一遍
[LUA-print] 走一遍
[LUA-print] 有函数
[LUA-print] 第三个分支
[LUA-print] 第一个分支
[LUA-print] 第二个分支
[LUA-print] 有函数
[LUA-print] 第三个分支
[LUA-print] 第三个分支
[LUA-print] 第一个分支
[LUA-print] 第二个分支
[LUA-print] 111
[LUA-print] 222
[LUA-print] nil
从结果可知,test 自己的属性wenqian3没有取出来,是空值,这是为何呢,经过分析代码能够知道,new的方法走了两次,
使得Sprite的对象的元类的index成了GameSprite,而GameSprite的元表的元表成了testClass,而不是元表的index是testClass,也就是说
Sprite的对象没法找到wenqian3字段,那么他就会去他元表的index字段,
也就是GameSprite中去找,可是GameSprite依然没法提供wenqian3,因此GameSprite去他的元表的index中
找,可是经过上面的程序得知GameSprite的元表的index不是testClass,因此没法找到他
因此综上所述得知,若是新建的类继承的直接是cocos系列的类,那么能够用好比直接写类名,或者返回create函数
而若是是继承的自定义的类,那么最简单,最直接的仍是直接写类名,而写函数的话,若是处理不当可能会出现奇怪的错误,固然函数也是能够实现的,具体状况须要具体分析