Lua如何像C++一样面向对象,从问题出现到解决,逐步了解为什么lua需要实现类

本文从以下几点分析逐步学习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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值