先了解一下原表 __index __newindex
__index
步骤1.在表中查找,如果找到,返回该元素,找不到则继续步骤2
步骤2.判断该表是否有元表,如果没有元表,返回nil,有元表则继续步骤3
步骤3.判断元表有没有__index方法,如果__index方法为nil,则返回nil;如果__index方法是一个表,则重复步骤1、2、3;如果__index方法是一个函数,则调用该函数,并返回该函数的返回值
__newindex 可以等于一个表 也可以等于一个函数
__newindex只会在添加原表没有的键值时才会调用
仔细思考C#面向对象的主要逻辑:封装 继承 多态
1.封装 多态: 一个class可以被new出来 new出来的对象只是拥有class的一些数据或函数的定义
在lua中local一下就好了
2.继承:可以被继承 重写 访问父类对象 在lua中 setmetatable(table, __index)就能实现
但需要注意的是lua中 在lua中如果函数调用在函数声明的前面 是访问不到的 可以通过__index来实现
下面这个类算是公司一直在用的 以及上线了的基类
不想暴露公司的源代码 类名以及一些其它的东西改了一下
如果需要用的话 建议仔细了解每行代码为什么这样些的原因 如果有不了解的 欢迎提问
local _class = {}
function NewClass(className, base)
-- 在创建对象的时候自动调用 在lua中local相当于C#的new
local oneClass = {
init = nil,
delete = nil,
name = className,
base = base,
}
oneClass.New = function(...)
-- 生成一个类对象 给外部提供的一个New方法 用来执行初始化函数 以及注册delete
local obj = {
_oneClass = oneClass
}
-- 在初始化之前注册基类方法
setmetatable(obj, {
__index = _class[oneClass],
})
-- 调用初始化方法
do
local function create(c)
if c.base then
create(c.base)
end
if c.init then
c.init(obj)
end
end
create(oneClass)
end
-- 注册一个delete方法
obj.delete = function(self)
local now_base = self._oneClass
while now_base ~= nil do
if now_base.delete then
now.delete(self)
end
now_base = now_base.base
end
end
return obj
end
--数据的内存地址不能一样 相当于new出来一个新的class类
local vtbl = {}
_class[oneClass] = vtbl
setmetatable(oneClass, {
__newindex = function(t,k,v)
vtbl[k] = v
end
,
--在lua中如果函数调用在函数声明的前面 是访问不到的 想要实现就通过__index 访问父类对象95行__index
__index = vtbl,
})
--有父类才需要访问父类 访问父类的父类的对象这样就能实现 因为如果有父类的父类 父类也是需要继承BaseClass
if base then
setmetatable(vtbl, {
__index = function(t,k)
--返回从_class缓存的数据
local ret = _class[base][k]
return ret
end
})
end
return oneClass
end
测试类
local a = NewClass("aaaaaaa")
function a:init()
self.aaaaa = "aaaaa"
end
local b = NewClass("bbbbb", a)
function b:init()
self.bbbbb = "bbbbb"
end
local c = NewClass("ccccc", b)
function c:init()
self.ccccc = "ccccc"
end
local c1 = c.New()
print("+++++++++c1", c1.ccccc)
print("+++++++++b", c1.bbbbb)
print("+++++++++a", c1.aaaaa)
参考
云风的博客 实现面向对象