本文从以下几点分析逐步学习lua面向对象编程思想
1.怎么解除对象间的依赖关系
2.lua中的语法糖 ’ : ’
3.lua中类的概念
4.lua中的单继承怎么实现
5.lua中的多继承怎么实现
在多继承之前的内容,都很好理解
学习建议:以下所有代码皆可运行,将所有代码都实现一遍。
先展示问题所在,将test1赋值给tt ,但test1释放后(赋值nil可以理解为舍弃), 就会出错
--
test1 = {val = 10}
function test1.fun()
test1.val = test1.val - 10
print(test1.val)
end
tt = test1
-- test1 = nil -- 如果把这句开启 就会出错
-- 因为test1已经复制nil了,但tt.fun仍会调用它
tt.fun()
以下这种方式,多传一个参数,就能解决上边的问题
test1 = {val = 10}
function test1.fun(self)
self.val = self.val + 20
print(self.val)
end
tt = test1
test1 = nil //就算赋值nil也不影响。
tt.fun(tt)
到这里,是不是觉得这个self功能其实很像C++中的this指针,就是将自己本身传递进去,lua中有一个语法糖’ : ’ 可以实现避免显式的写出self对象。
比如上边是 tt.fun(tt), 可以通过tt : fun(), 从而省去tt的传参
test1 = {val = 10}
function test1:fun()
self.val = self.val + 10
print("self:"..self.val) -- 如果把.. 换成, 相当于一个'\t'
end
tt = test1
test1 = nil
tt:fun()
是不是越来越有对象的感觉了。
lua中类的概念 : 我们需要实现一个类, 然后通过这个类来初始化一个对象
lua中面向对象的编程思想最重要的就是, 关于元表的设计,以及元方法(__index)的设计
比如 setmetatable(o, self) , self就是o的元表, 然后再给self设置元方法。
在下边的代码中 new() 函数相当于返回了一个我们需要的对象,关于这个对象所具有的功能,是封装在acount中的,所以我们可以把acount当作类。
local acount = {val = 10}
function acount:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
function acount:display()
self.val = self.val + 200
print(self.val)
end
local a = acount:new{val = 0} -- a 就相当于 acount类的一个对象
--这里改成local a = acount:new() 看一下输出结果
--lua中当传参是一个表的时候可以省略 ()
a:display() --等价a.display(a)
-- 我这里是给了初始表 {val = 0},
-- 若没有给初始表,比如上边换成acount:new(),则a本来是没有val对象的,a.val 就相当于 getmetatable(a).__index(val) 才能得到val
--第一次调用display时,self.val 就是 a.val 尽管是去acount中获取的val,
但是因为调用了a.val,就相当于在a中添加了一个新的字段val,当第二次调用display时,就不会去acout中寻找val字段了,而是直接用a对象自己的val
lua中的单继承实现
简单分析流程:先创建父类acount, 子类acount_son是通过acount:new()获得的
再通过acount_son:new () 返回的就是子类acount_son的一个对象
下边的代码中还实现了,在子类acount_son中重写父类acount的display方法。
local acount = {val = 10}
function acount:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
function acount:display()
self.val = self.val + 100
print(self.val)
end
acount_son = acount:new()
function acount_son:display() -- 相当于类中的函数重写
self.val = self.val + 666
print(self.val)
end
ins = acount_son:new()
ins:display()
-- 可以分析一下,ins.val第一次是没有的,先去acount_son再去acount找的
-- 同样ins.display也是一样, 但如过在acount_son中重写了display函数,就相当于实现了重写的效果
lua中的多重继承实现
简单流程分析: 通过上边的演示,我们已经知道了lua的面向对象实质上就是通过__index元方法实现的, 只是对于单继承,直接是self.__index = self,
而多继承中,不能直接 =self ,而是用一个函数,来遍历所继承的所有父类中的方法。
其实不用想的太复杂,多继承和单继承的本质区别就是
setmetatable(c, {__index = function(t,k) return search(k, parentlist) end})
在子类继承父类的时候(c继承CA,CB),不再是像单继承一样self.__index = self了
还有一个关键的细节点, c是子类,我们需要用c返回一个对象**,和单继承返回对象一样**,所以需要实现c:new() ,发现没有,单继承和多继承的区别就在于继承父类的时候__index的设置不同,但生成对象都是一样的方式
local function search(k, parentlist)
for i = 1, #parentlist do
local fun = parentlist[i][k]
if fun then
return fun
end
end
end
function createclass(...)
local parentlist = {...}
local c = {}
setmetatable(c, {__index = function(t,k) return search(k, parentlist) end})
function c:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
-- 返回新的类
return c
end
-- 简单类CA
local CA = {}
function CA:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
function CA:SetName(strName)
self.name = strName
end
-- 简单类CB
local CB = {}
function CB:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
function CB:GetName()
return self.name
end
--创建一个c类, 它的父类是CA 和 CB
local c = createclass(CA, CB)
--使用c类创建一个实例对象
local objectc = c:new{name = "jj"}
--设置objectc的新名字
objectc:SetName("dashuaigejj")
local newName = objectc:GetName()
print(newName)