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函數
而若是是繼承的自定義的類,那麼最簡單,最直接的仍是直接寫類名,而寫函數的話,若是處理不當可能會出現奇怪的錯誤,固然函數也是能夠實現的,具體狀況須要具體分析