lua实现类的继承

学过java或者C++的小伙伴肯定知道什么是继承,因为继承是面向对象的一大特征。面向过程的语言就不能实现继承了,lua也是一样。不过lua强大的table可以利用元表模拟出继承的功能。下面我就说下一如何用lua实现面向对象中继承的功能。

什么是继承?

曹操是三国时期杰出的政治家,文学家,书法家,军事家。总之这人很牛X!他的儿子们也都各有所长,为什么要说他的儿子们呢?因为:

曹丕:继承了曹操的政治和谋略
曹植:继承了曹操的天赋和才华
曹冲:继承了曹操的聪明和智慧
曹彰:继承了曹操的勇气和胆识
曹昂:被亲爹坑了

这种就叫继承。儿子们没有父亲的特征就没有继承。

理解lua查找元表的过程

举例说明:
Lua的表本质其实是个类似HashMap的东西,其元素是很多的Key-Value对,如果尝试访问了一个表中并不存在的元素时,就会触发Lua的一套查找机制,也是凭借这个机制来模拟了类似“继承”的行为

Caocao = {}
print(Caocao.Wife) --这里试图打印曹操的老婆,但是并没有。

执行结果:nil

输出为nil的原因很简单,Caocao中并没有Wife这个成员,这符合我们平时对HashMap的认知。但对于Lua表,如果Caocao有元表,情况就不同了。

举个栗子:

Caocao = {
	kill = "吕布"  --曹操杀了吕布
}
son = {
	surname = "cao"  --儿子们都姓曹
}
setmetatable(son, Caocao) --把son的metatable设置为Caocao
print(son.kill)

输出的结果是nil,儿子们没有杀吕布。但如果把代码改为

Caocao = {
	kill = "吕布"  --曹操杀了吕布
}

Caocao.__index = Caocao   --把Caocao的__index方法指向自己

son = {
	surname = "cao"  --儿子们都姓曹
}
setmetatable(son, Caocao) --把son的metatable设置为Caocao
print(son.kill)

输出的结果为1,符合预期

这样一来,结合上例,来解释__index元方法的含义:

在上述例子中,访问son.kill时,son中没有kill这个成员。但Lua接着发现son有元表Caocao。

注意:这时候,Lua并不是直接在Caocao中找名为kill的成员,而是调用Caocao的__index方法,如果__index方法为nil,则返回nil,如果是一个表的__index方法等于自己,那么就到__index方法所指的这个表中查找名为kill的成员,于是,最终找到了kill成员。

注:__index方法除了可以是一个表,还可以是一个函数,如果是一个函数,__index方法被调用时将返回该函数的返回值。

到这里,总结一下Lua查找一个表元素时的规则,其实就是如下3个步骤:

1.在表中查找,如果找到,返回该元素,找不到则继续

2.判断该表是否有元表(操作指南),如果没有元表,返回nil,有元表则继续

3.判断元表(操作指南)中有没有关于索引失败的指南(即__index方法),如果没有(即__index方法为nil),则返回nil;如果__index方法是一个表,则重复1、2、3;如果__index方法是一个函数,则返回该函数的返回值

理解了lua查找元表的过程,下面用实际的案例来进一步说明。

曹植对于曹操的继承案例

首先,我们建一个类,名称为Caocao.lua(曹操),定义两个属性分别为surname—姓,name—名,定义四个方法分别为wisdom—智慧,talent—才华,strategy—谋略,courage—胆识。

Caocao={}  --初始化曹操

function Caocao:new() --相当于java中曹操的构造方法
    local nc={
      surname = "Cao", --姓
      name = "cao",    --名
    }
    setmetatable(nc,self) --元表,当子类调用其没有的属性或者方法时,会查找该元表的setmetatable,然后发现子类的元表为父类。(因为返回值赋给曹植,所以nc此时就是曹植,)
    self.__index = self  --接着发现父类有“_index”而且索引指向父类本身,所以子类在找不到属性或者方法时会来父类找。
    return nc       --返回给子类
end

function Caocao:wisdom()  --智慧
    print("曹操的智慧")
end

function Caocao:talent()  --才华
    print("曹操的才华")
end

function Caocao:strategy()--谋略
    print("曹操的谋略")
end

function Caocao:courage() --胆识
    print("曹操的胆识")
end

创建一个子类Caozhi.lua(曹植),定义一个属性:name—名,三个方法wisdom—智慧,strategy—谋略,courage—胆识。

为什么这样定义?因为曹植姓曹,且才华横溢,这些都是继承了曹操。这些用曹操的就行。下面看曹植的代码

require "Caocao"   --导入曹操
Caozhi = Caocao:new()   --初始化曹植

Caozhi.name = "zhi"    -- 曹植的名

function Caozhi:wisdom()  --没有智慧
    print("")
end

function Caozhi:strategy()--没有谋略
    print("")
end

function Caozhi:courage() --没有胆识
    print("")
end


print(Caozhi.surname..Caozhi.name) --看看有没有继承曹操的姓并且用自己的名

Caozhi:talent()  --继承的才华

Caozhi:courage()  --胆识

打印结果:
在这里插入图片描述
结果符合预期。功能和面向对象中的一致,不同的地方在于lua是通过查找表元素实现的继承。就像我在Caocao.lua中注释的那样,曹植最开始就调用了曹操的构造方法,并将setmetatable中的第一个参数nc赋值给曹植,这样曹植的元表就是曹操了,同时曹操的元表又指向自己,所以曹植没有的属性或者方法会调用曹操的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值