新旧版class函数对比

撰写于 2018-05-07 修改于 2018-05-09

目前我们游戏中使用的是cocos2d-x3.3,已经很老了,无意间看到了新版class函数的定义,函数的书写形式有很大变化,但是思想没什么大的变化。细节上的处理还是比老版class跟考究一点。

实现了多继承

其实所谓的多继承,就是在__index上下了做了点文章,也只针对父类是纯lua的table,核心的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
cls.__index = cls
if not cls.__supers or #cls.__supers == 1 then
setmetatable(cls, {__index = cls.super})
else
setmetatable(cls, {__index = function(_, key)
local supers = cls.__supers
for i = 1, #supers do
local super = supers[i]
if super[key] then return super[key] end
end
end})
end

大致解释一下,如果cls中找不到变量或者函数,则会从继承的父类中查找该变量或函数。

cls.new函数

还有一个处理也是很精妙的地方,就是cls.new函数,下面附上老版和新版的:

  1. 老版

    1
    2
    3
    4
    5
    6
    7
    8
    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
  2. 新版

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    cls.new = function(...)
    local instance
    if cls.__create then
    instance = cls.__create(...)
    else
    instance = {}
    end
    setmetatableindex(instance, cls)
    instance.class = cls
    instance:ctor(...)
    return instance
    end

在这里只说明一下native object,老版的创建对象的方法是,先调用create函数,如果父类是function的话,\create就是该function,如果不是function,则基类一定会是一个function,调用该function,会生成一个userdate类型的对象,然后把改cls的所有方法和变量都拷贝进该对象,保证该对象中变量和方法是独立的,当然方法也会拷贝进去,这其实是一个缺点,我们不需要拷贝方法。新版的class函数做了优化,把所有的继承操作放在了setmetatableindex中进行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
setmetatableindex_ = function(t, index)
if type(t) == "userdata" then
local peer = tolua.getpeer(t)
if not peer then
peer = {}
tolua.setpeer(t, peer)
end
setmetatableindex_(peer, index)
else
local mt = getmetatable(t)
if not mt then mt = {} end
if not mt.__index then
mt.__index = index
setmetatable(t, mt)
elseif mt.__index ~= index then
setmetatableindex_(mt, index)
end
end
end

每个C++对象需要存贮自己的成员变量的值,这个值不能够存贮在元表里(因为元表是类共用的),所以每个对象要用一个私有的表来存贮,这个表在tolua里叫做peer表。元表的__index指向了一个C函数,当在Lua中要访问一个C++对象的成员变量(准确的说是一个域)时,会调用这个C函数,在这个C函数中,会查找各个关联表来取得要访问的域,这其中就包括peer表的查询。

如果生成的对象instance是userdata,则查看是否有peer,peer就是为该对象的一个独立空间,如果没有就生成一个table,然后设置peer,然后把该cls设置为该peer的metatable

Site by ZHJ using Hexo & Random

Hide