众所周知,lua没有类这个概念但其通过table实现了面向对象的“类”。在cocos2dx引擎下提供了class(className, ...)函数方法名,因为在脚本开发中这个接口基本都会用来创建一个lua对象,所以很重要。在之前的求职面试中,也有一些公司问到了这个实现的问题,如“lua中定义的class,使用了lua的哪些特性; 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", {})
下面就3.x逐行源码进行详细分析。
function class(classname, ...) local cls = {__cname = classname} --多继承 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)) if superType == "function" then assert(cls.__create == nil, string.format("class() - create class \"%s\" with more than one creating function", classname)); cls.__create = super elseif superType == "table" then --若有.isclass这个值则说明是从c++转换过来的数据结构 if super[".isclass"] then assert(cls.__create == nil, string.format("class() - create class \"%s\" with more than one creating function or native class", classname)); cls.__create = function() return super:create() end else -- lua表 cls.__supers = cls.__supers or {} cls.__supers[#cls.__supers + 1] = super if not cls.super then cls.super = super end end else error(string.format("class() - create class \"%s\" with invalid super type", classname), 0) end end --lua元表:实现继承的重要元素,__index "查询"当子类搜索自己的函数未果,会按照__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 cls.new = function(...) local instance if cls.__create then --C++层/lua方法 instance = cls.__create(...) else instance = {} end setmetatableindex(instance, cls) instance.class = cls instance:ctor(...) return instance end cls.create = function(_, ...) return cls.new(...) end return cls end