0基础lua学习(十六)lua的多态 base
多态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_type
end
--main.lua代码
require"base"
father = father or BaseClass()
function father:__init()
print("father:init")
end
function father:Bind()
print("father:Bind")
end
function father:play()
print("father:play")
end
son = son or BaseClass(father)
function son:__init()
print("son:init")
end
function son:Bind()
print("son:Bind")
end
function son:UnBind()
end
a = nil
a = 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 ret
end
_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代码。