新旧版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
12cls.__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
2
3
4
5
6
7
8function 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新版
1
2
3
4
5
6
7
8
9
10
11
12cls.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
19setmetatableindex_ = 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