在lua中,可以通过元表来实现类、对象、继承等。与元表相关的方法有setMetatable()、__index、getMetatable()、__newindex。
关键:实现Lua面向对象可以分解为类的定义和类的实例化两个问题。类的定义主要是实现继承,即怎么让子类拥有父类的方法集。类的实例化需要解决实例如何共享类的方法集,但独享自己的成员变量实例。
方案:子类在定义时复制所有基类的方法,在实例化时将该类作为Metatable的__index赋值给实例。这就是cocos2dx里面的lua class的实现。
function clone(object)--clone函数 local lookup_table = {}--新建table用于记录 local function _copy(object)--_copy(object)函数用于实现复制 if type(object) ~= "table" then return object ---如果内容不是table 直接返回object(例如如果是数字\字符串直接返回该数字\该字符串) elseif lookup_table[object] then return lookup_table[object]--这里是用于递归滴时候的,如果这个table已经复制过了,就直接返回 end local new_table = {} lookup_table[object] = new_table--新建new_table记录需要复制的二级子表,并放到lookup_table[object]中. for key,value in pairs(object) do new_table[_copy(key)] = _copy(value)--遍历object和递归_copy(value)把每一个表中的数据都复制出来 end return setMetatable(new_table,getMetatable(object))--每一次完成遍历后,就对指定table设置Metatable键值 end return _copy(object)--返回clone出来的object表指针/地址 end --[[ clone 深度克隆一个值。 格式:value = clone(值) 用法示例: -- 下面的代码,t2 是 t1 的引用,修改 t2 的属性时,t1 的内容也会发生变化 local t1 = {a = 1,b = 2} local t2 = t1 t2.b = 3 -- t1 = {a = 1,b = 3} <-- t1.b 发生变化 -- clone() 返回 t1 的副本,修改 t2 不会影响 t1 local t1 = {a = 1,b = 2} local t2 = clone(t1) t2.b = 3 -- t1 = {a = 1,b = 2} <-- t1.b 不受影响 --]] --Create an class. function class(classname,super)--super为继承的类 local superType = type(super) local cls --如果父类既不是函数也不是table则说明父类为空 if superType ~= "function" and superType ~= "table" then superType = nil super = nil end --如果父类的类型是函数或者是C对象 if superType == "function" or (super and super.__ctype == 1) then -- inherited from native C++ Object cls = {} --如果父类是表则复制成员并且设置这个类的继承信息 --如果是函数类型则设置构造方法并且设置ctor函数 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 --定义该类型的创建实例的函数为基类的构造函数后复制到子类实例 --并且调用子数的ctor方法 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 --如果是继承自普通的lua表,则设置一下原型,并且构造实例后也会调用ctor方法 -- 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通过该方法,我们可以很方便的定义一个class、继承一个class。
--声明一个类: MyClass = class("MyClass") function MyClass:ctor() print("MyClass:ctor()") end --定义一个对象 local myclass = MyClass:new() --继承一个类: --继承一个函数 GameLayer = class("GameLayer",function()local layer = cc.Layer:create() return layer end) local gamelayer = GameLayer:new()
ctor=constructor(构造函数)
dtor=destructor(析构函数)
1.在子类构造函数ctor()中要调用父类构造函数ctor(),这用self.super:ctor(param),这句话反应出并不会像C++那样,在创建子类实例时,自动调用父类的构造函数。
2.使用class(classname,super)来子类继承父类只会继承父类的成员函数,而不会继承父类的成员变量。
若要子类既要继承父类的成员函数也要继承父类的成员变量,且在创建子类实例时,自动调用父类的构造函数。这用下面的class(classname,super)
function class(classname,super) local cls = {} if super then cls = {} for k,v in pairs(super) do cls[k] = v end cls.super = super else cls = {ctor = function() end} end cls.__cname = classname cls.__index = cls function cls.new(...) local instance = setMetatable({},cls) local create create = function(c,...) if c.super then -- 递归向上调用create create(c.super,...) end if c.ctor then c.ctor(instance,...) end end --create(instance,...)--若替换成instance:ctor(...)则先调用自己的构造函数,若自己没有,则调用父类的构造函数 instance:ctor(...) instance.class = cls return instance end return cls end local BaseClass = class("BaseClass",nil) function BaseClass:ctor(param) print("baseclass ctor") self._param = param self._children = {} end function BaseClass:addChild(obj) table.insert(self._children,obj) for k,v in ipairs(self._children) do print(k,v) end end local DerivedClass = class("DerivedClass",BaseClass) function DerivedClass:ctor(param) print("derivedclass ctor") end local instance = DerivedClass.new("param1") instance:addChild("child1") --打印输出 --baseclass ctor --derivedclass ctor --1 child1极具有参考价值的文章: Lua 面向对象实现
扩展阅读:Lua的面向对象程序设计