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 --保护元表

 

 

 参考:

userdate和table类型的效率对比

class语法糖要注意了

cocos-lua学习笔记(五)cocos2d-Lua类的实现

Lua中的元表与元方法学习总结

posted @ 2018-08-23 00:07  _raindrop  阅读(1221)  评论(0编辑  收藏  举报