0基础lua学习(十六)lua的多态 base

来源:互联网 发布:ubuntu win7双系统安装 编辑:程序博客网 时间:2024/06/04 08:26

多态base

使用lua实现C++类似的多态,看起来略微难了一些,这个demo,默认提供了 init类似构造函数的时机。

--base.lua代码--保存类类型的虚表local _class = {}function BaseClass(super)    -- 生成一个类类型    local class_type = {}    -- 在创建对象的时候自动调用    class_type.__init = false    class_type.__delete = false    class_type.super = super    class_type.New = function(...)        -- 生成一个类对象        local obj = {}        obj._class_type = class_type        -- 在初始化之前注册基类方法        setmetatable(obj, { __index = _class[class_type] })        -- 调用初始化方法        do            local create            create = function(c, ...)                if c.super then                    create(c.super, ...)                end                if c.__init then                    c.__init(obj, ...)                end            end            create(class_type, ...)        end        -- 注册一个delete方法        obj.DeleteMe = function(self)            local now_super = self._class_type            while now_super ~= nil do                if now_super.__delete then                    now_super.__delete(self)                end                now_super = now_super.super            end        end        return obj    end    local vtbl = {}    _class[class_type] = vtbl    setmetatable(class_type, {__newindex =    --table key value        function(t,k,v)            vtbl[k] = v        end        ,        __index = vtbl, --For call parent method    })    if super then        setmetatable(vtbl, {__index =            function(t,k)                local ret = _class[super][k]                return ret            end        })    end    return class_typeend
--main.lua代码require"base"father = father or BaseClass()function father:__init()    print("father:init")endfunction father:Bind()    print("father:Bind")endfunction father:play()    print("father:play")endson = son or BaseClass(father)function son:__init()    print("son:init")endfunction son:Bind()    print("son:Bind")endfunction son:UnBind()enda = nila = son:New()a:play()a:Bind()

console:
father:init
son:init
father:play
son:Bind

多态base解析

1.首先要明确
father = father or BaseClass( )和 son = son or BaseClass(father)
有一个共同的表local _class = {},也就是虚表。

2.father = father or BaseClass(),我们会保存__class[class_type] = vtbl
classtype是key,value是表
返回的表是 class_type

                vtbl                 {__newindex =                    function(t,k,v)                           vtbl[k] = v                    end,                  __index = vtbl                 }

3.function father:__init(),会将class_type表中的__init 从布尔,变为函数
4.function father:Bind(),没有Bind函数,所以会调用vtbl表中的__newindex,因为我们没有Bind的key

    function(t,k,v)           vtbl[k] = v    end

这样vtbl中添加了一个Bind的key,value是函数
5.son = son or BaseClass(father)同理,但是它的vtbl会添加__index = function(t,k)的函数

6.function son:__init(),会将class_type表中的__init 从布尔,变为函数
7.function son:Bind(),所以会调用

    function(t,k,v)           vtbl[k] = v    end

向son的vtbl表中加入函数
8.a = son:New()这是
son = son or BaseClass(father)里面的new方法,调用父类的init,然后调用子类的init,然后返回
_class[class_type],这个是son的vtbl表。(_class里面有两个vtbl,key分别是father的class_type和son的class_type,其值是各自的vtbl表)

9.a:play()这是调用父类的play方法,首先去son的vtbl表中查找,通过__index调用了

function(t,k) local ret = _class[super][k] return retend

_class[super]这是访问虚表中的,father的vtbl,然后我们找到了,然后进行调用。
注意:如果我们换成a:play1(),就会报错all method ‘play1’ (a nil value) ,也就是你声明函数,要加到父类的表里
也就是下面这步

function father:play()    print("father:play")end

10.a:Bind(),其实就是找son的vtbl,直接找到了函数,然后调用。

小结:

  • 我们声明的 son继承 father之前,需要创建两个表,每个表里都有一个vtbl , 有一个总表_class来管理
  • __newindex 实现的是,我们创建函数添加函数,加到vtbl 表里
  • __index 实现的是,继承的实现。即访问父类里面的函数,如果子类实现了,就访问子类的。
  • t 是table、k是key、v是value

看着是有点乱,但是你多看几遍,你就会有所收获。
这个代码可以说,我们在开发游戏的时候,使用的base代码。