zoukankan      html  css  js  c++  java
  • 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中的元表与元方法学习总结

  • 相关阅读:
    尾递归
    Appium环境搭建
    虚拟机与主机的相互访问,虚拟机访问外网
    Python
    npm i 安装
    redis过期键删除策略
    Redis的过期策略和内存淘汰机制
    redis的两种持久化方案
    JVM 方法内联
    进程/线程/协程
  • 原文地址:https://www.cnblogs.com/losophy/p/9521248.html
Copyright © 2011-2022 走看看