lua:lua面向对象
lua中可以通过修改元表元方法来实现面向对象。
而table中的self相当于this。
lua中的table就是一种对象。
首先,table与对象一样可以拥有状态。
其次,table也与对象一样拥有一个独立于其值的标识(一个self)。
最后,table与对象一样具有独立于创建者和创建地的生命周期。
function Account:withdraw(v) self.balance = self.balance - v end
lua只需使用冒号,则能隐藏self参数。
类
一个类就像是一个创建对象的模具。我们可以利用__index元方法构造继承。
当访问一个table中不存在的字段时,得到的结果为nil。这是对的,但并非完全正确。实际上,这些访问会促使解释器去查找一个叫__index的元方法。如果没有这个元方法,那么访问结果如前述的为nil。否则,就由这个元方法来提供最终结果。
在lua中,将__index元方法用于继承很普遍,__index还可以是一个table。
setmetatable(a,{--index=b})
function Account:new(o) o = o or {} --如果用户没有提供table,则创建一个 setmetatable(o,self) self.__index = self return o end
之前写过一篇关于lua实现面向对象的文章,借助元表和元方法实现,感觉也是有点乱。
我们可以参考cocos2d-x自己给出的类的实现,也即在luaBinding目录下extern.lua的文件中给出的实现:
function class(classname, super) --superType获取父类类型,可以使nil、function以及table. 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 = {} --如果父类是表则复制成员并且设置这个类的继承信息 if superType == "table" then -- 从父类copy 字段 print ("superTyper is table"); for k,v in pairs(super) do cls[k] = v end cls.__create = super.__create cls.super = super else --如果是函数类型则设置构造方法并且设置ctor函数 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
创建对象时,可以通过className.new这种方式来创建,如
local MySpriteClass = class("MySpriteClass",cc.Sprite) function MySpriteClass:ctor() end return MySpriteClass
mySpriteClass 实例创建
local mySprite = MySpriteClass.new(xxx.png)
来自某书上的图
classname.new()生成的instance包含一个class属性。class指向了类原型,并具有super,ctor,__cname和__ctype 4个属性
继承C++的类,new方法使用__create函数来创建实例
继承lua类,new方法使用{ }来创建实例。
继承Lua的类,new方法使用{ }来创建实例。
一些概念
UserData(用户自定义类型)
意义:使用C语言编写的用于扩展Lua的新类型,方便使用脚本编写或者提高效率
userdata:提供了一块原始的内存区域,用于存储任何东西,在Lua中userdata没有任何预定义操作
生成:void *lua_newuserdata(L,size) 根据指定大小分配一块内存,并将userdata压入栈中,最后返回这个内存块的地址
元表和元方法
在Lua中有一个元表,也就是上面说的metatable,我们可以通过元表来修改一个值得行为,使其在面对一个非预定义的操作时执行一个指定的操作。比如,现在有两个table类型的变量a和b,我们可以通过metatable定义如何计算表达式a+b
我们是使用getmetatable来获取一个table或userdata类型变量的元表,当创建新的table变量时,使用getmetatable去获得元表,将返回nil;同理,我们也可以使用setmetatable去设置一个table或userdata类型变量的元表
在table中,我可以重新定义的元方法有以下几个:
__add(a, b) --加法 __sub(a, b) --减法 __mul(a, b) --乘法 __div(a, b) --除法 __mod(a, b) --取模 __pow(a, b) --乘幂 __unm(a) --相反数 __concat(a, b) --连接 __len(a) --长度 __eq(a, b) --相等 __lt(a, b) --小于 __le(a, b) --小于等于 __index(a, b) --索引查询 __newindex(a, b, c) --索引更新(PS:不懂的话,后面会有讲) __call(a, ...) --执行方法调用 __tostring(a) --字符串输出 __metatable --保护元表
参考: