class() 高階用法 --cocos2dx- lua
在quick-cocos2dx裡, 通過class() 函式進行類的定義
下面貼出quick-cocos2d-x-2.2.1-rc 裡 class()的原始碼
function class(classname, super)
local superType = type(super)
local cls
if superType ~= "function" and superType ~= "table" then
superType = nil
super = nil
end
if superType == "function" or (super and super.__ctype == 1) then
-- inherited from native C++ Object
cls = {}
if superType == "table" then
-- copy fields from super
for k,v in pairs(super) do cls[k] = v end
cls.__create = super.__create
cls.super = super
else
cls.__create = super
cls.ctor = function() end
end
cls.__cname = classname
cls.__ctype = 1
function cls.new(...)
local instance = cls.__create(...)
-- copy fields from class to native object
for k,v in pairs(cls) do instance[k] = v end
instance.class = cls
instance:ctor(...)
return instance
end
else
-- inherited from Lua Object
if super then
cls = {}
setmetatable(cls, {__index = super})
cls.super = super
else
cls = {ctor = function() end}
end
cls.__cname = classname
cls.__ctype = 2 -- lua
cls.__index = cls
function cls.new(...)
local instance = setmetatable({}, cls)
instance.class = cls
instance:ctor(...)
return instance
end
end
return cls
end
我們先考慮最簡單的情況, 在沒有繼承的情況下定義一個類ClassA
--ClassA.lua local ClassA = class("ClassA") ClassA.field1 = "this is field1" return ClassA
--main.lua local ClassA = require("ClassA") local InstanceA = ClassA.new()
這種情況下, ClassA 跟InstanceA的關係如下圖
InstanceA的metatable為ClassA, 而且ClassA.__index = ClassA, 因此,對於InstanceA找不到的屬性, 將在ClassA裡進行查詢。 需要注意的是,ClassA裡的屬性比如field1, 是相當於類變數的概念,所有例項都公用該屬性,並非各自維護該欄位的拷貝。
下面如果要再定義ClassB, 從ClassA 進行繼承
--ClassB.lua
local ClassB = class("ClassB", require("ClassA"))
return ClassB
這種情況下, ClassB 跟InstanceB, ClassA的關係如下圖
同理,InstanceB裡沒有定義的屬性, 將首先在ClassB裡進行搜尋, 如果ClassB裡搜不到, 將向上追尋到ClassA裡。
上面考慮的都只是針對純Lua類, 在實際情況中, 我們需要對C++裡生成的物件(userdata)進行擴充套件, 可以如下定義
--ClassC.lua
local ClassC = class("ClassC", function()
--呼叫C++介面建立一個原生物件(userdata), 並且給該物件繫結一個peer(table), 這裡我們以建立一個CCNode為例
local node = CCNode:create() --原生物件(userdata)
local peer = {}
tolua.setpeer(node , peer )
return node
end)
return ClassC
ClassC跟InstanceC的關係如下圖
在呼叫InstanceC(實際上是一個userdata)上的某個方法時, 首先會先去這個userdata繫結的peer這個table裡尋找這個方法,如果找不到才會去c++那層呼叫。
所以我們可以通過給peer新增幾個方法從而實現給InstanceC(userdata)擴充套件方法, 實際情況上也確實如此,在quick裡,有幾個專門的類,CCNodeExtend,CCLayerExtend,CCSceneExtend,CCSpriteExtend, 使用比如 CCNodeExtend.extend(someCCNodeInstance), 可以生成一個特殊的peer, 這個peer的metatable為CCNodeExtend, 這樣我們就可以在someCCNodeInstance上呼叫CCNodeExtend定義了而原本CCNode沒有的方法, 從而實現擴充套件。
下面再考慮ClassD從ClassC繼承的情況
--ClassD.lua
local ClassD = class("ClassD", require("ClassC"))
return ClassD