lua 模拟面向对象的继承通常是通过class方法,今天简析一下对class的理解,先例子
local MyApp = class("MyApp", cc.load("mvc").AppBase)
这是MyApp里的一个方法继承语句,class方法内部两个参数,一个是新建类简称A ,另一个是A继承的父类的类简称B,这句代码可以使得生成的A类继承B类后返回名为MyApp的新的子类。
重点内容
问题,class方法是如何实现模拟lua继承的呢?
class有三种继承情况,
1、第一种是继承一个方法,
local LogoScene = class("LogoScene", function()
return cc.Scene:create()
end)
2、第二种继承一个C语言原生类
local LogoScene = class("LogoScene", cc.Scene)
3、继承一个lua类
local LogoScene = class("LogoScene", {})
下面看一下面class的代码
function class(classname, ...)
local cls = {__cname = classname}
--这里可以看出lua的cocos模拟的class方法支持多继承
local supers = {...}
for _, super in ipairs(supers) do
local superType = type(super)
assert(superType == "nil" or superType == "table" or superType == "function",
string.format("class() - create class \"%s\" with invalid super class type \"%s\"",
classname, superType))
--这里是class继承的第一种情况,继承一个方法(在子类new之前先执行的内建函数__create)
if superType == "function" then
assert(cls.__create == nil,
string.format("class() - create class \"%s\" with more than one creating function",
classname));
-- if super is function, set it to __create
--如果super是一个方法,把super直接复制给内建函数__create
cls.__create = super
--下面是class的第二,第三种情况,当传过来的值是table类型的时候
--这里需要明确的一点是,在lua里table其实还分两种,一种是lua的table,另一种是c里转换过来的一种类型叫userTable,在用tolua++绑定cocos2dx引擎的时候,tolua++会为userTable类型的类在执行create方法的时候为其加入.isclass属性(大家可以用执行dump(cc.Layer)观察)
elseif superType == "table" then
--下面这种是第二种情况
--如果有.isclass这个值则说明是从c++转换过来的数据结构
if super[".isclass"] then
-- super is native class
assert(cls.__create == nil,
string.format("class() - create class \"%s\" with more than one creating function or native class",
classname));
--这里可以看出这种继承了c结构的子类其实也只是执行子类之前执行了一个创建父类对象的方法
cls.__create = function() return super:create() end
else
--后面这个是第三种情况,子类是lua继承的父类也是lua,这里有另一个内建函数__supers,他的作用是存放父类数组(父类可能不止一个)
-- super is pure lua class
cls.__supers = cls.__supers or {}
cls.__supers[#cls.__supers + 1] = super
if not cls.super then
-- set first super pure lua class as class.super
cls.super = super
end
end
else
error(string.format("class() - create class \"%s\" with invalid super type",
classname), 0)
end
end
--__index方法是一个“操作指南”
--下面的__index对于继承功能的模拟也很关键
--更简单的说就是在我调用方法的时候,class是如何实现继承功能的(当子类搜索自己的函数未果,就会按照__index的指引去搜索父类,去寻找方法)
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
if not cls.ctor then
-- add default constructor
cls.ctor = function() end
end
--这里的new方法是模拟cocos2dx里面的创建对象,下面的代码一目了然
cls.new = function(...)
local instance
if cls.__create then
--这里需要注意的一件事是,
--
--local LogoScene = class("LogoScene", function(argu)
-- --dump(argu)
-- return cc.Scene:create()
--end)
--function LogoScene:ctor(argu)
-- --dump(argu)
--end
--上面的和这个栗子如果调用 LoginScene:create(argu)方法会将argu里的参数传到class后面的function里面,执行完function之后再执行ctor。
instance = cls.__create(...)
else
instance = {}
end
setmetatableindex(instance, cls)
instance.class = cls
instance:ctor(...)
return instance
end
--这里只是为了模拟cocos2dx的编程习惯
cls.create = function(_, ...)
return cls.new(...)
end
return cls
end
到这里class的基本用法就写完了,usertable找个数据结构涉及到lua虚拟机内部的结构,后面研究透彻之后会继续补充。
2017.2.6