1. 程式人生 > >class() 高階用法 --cocos2dx- lua

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