今天学习lua实现oop,主要参考了云风的博客点击打开链接和半山无极点击打开链接两个人里面写的。通过__index和__newindex这两种元方法的使用。
每个类都有一张虚表来存储基类的信息(_class)。通过new方法来创建对象。为每个类类型设置元表,它的索引方式就是__index和__newindex。这两种索引可以包含函数和表。__newindex是函数的时候,会传递表、索引、值三个参数。通过__index可以索引父类的所有方法,基类的方法通过__newindex进行初始化(赋值,声明方法)
--保存类类型的虚表
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] })
-- 注册一个delete方法
if(super and not super.DeleteMe) then
obj.DeleteMe = function(obj_self)
local now_super = obj_self._class_type
while now_super ~= nil do
if now_super.__delete then
now_super.__delete(obj_self)
end
now_super = now_super.super
end
end
end
-- 调用初始化方法
class_type.__init(obj, ...)
return obj
end
local vtbl = {}
_class[class_type] = vtbl
setmetatable(class_type, {__newindex =
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]
--do not do accept, make hot update work right!
--vtbl[k] = ret
return ret
end
})
end
return class_type
end
通过 A = BassClass()创建了对应的基类,基类的方法通过__newindex把它的成员函数和数据进行初始化(如果基类没有成员函数或者数据,事件将不会被触发),使用虚表把基类保存在_class中,通过虚表添加自身的索引,实现子类访问父类的所有方法。如果在newindex里面没有添加__index = vtbl,那么子类不通过实例化对象访问没有重载父类的函数会报错,添加以后子类可以访问,实现了热更新。 通过 B = BassClass(A)创建了A的子类,子类对象通过__index访问父类_class[A] [k] 的所有方法。子类B通过new方法创建对象,创建的子类对象通过元表中__index注册了父类的所有方法。在上面的函数中还给子类对象添加了一个delete函数,类似c++里面的析构函数。最后初始化这个子类对象。