Lua继承的实现

  • 最简单的继承
-- 创建Person表,默认有name,gender,age三个属性以及一个cry()方法
Person = {name = "小明", gender = "F", age = 18}
function Person:cry()
    print(self.name, "crying... @.@")
end

-- 创建per空表
per = {}

-- 让per继承Person仅需有两步
-- 1、创建一个表pmt作为per的元表
pmt = {__index = Person}
-- 2、将per的metatable设置为pmt
setmetatable(per, pmt)

-- 两步合成一步 即:setmetatable(per, {__index = Person})

-- 此后per就拥有Person的成员变量和方法了
print(per.name)	--> 小明
per:cry()	--> 小明crying... @.@


-- 以上是最简单的继承,就像一个对象继承自类对象一样,此处可以把Person当做类,把per当做对象
-- 这样写的目的是让大家对下面将要提到的通过类初始化对象有个清晰的认识,开发过程中几乎不这样写
  • 如何定义类以及构造方法
-- 定义一个Person类,包含默认值name,gender, age
Person = {name = "小明", gender = "F", age = "0"}
-- 构造方法
function Person:new(o)
    -- self为调用方法者,故此处self为Person
    -- o为继承Person的对象(本质是lua table)
    o = o or {}			-- o不为nil,则o = o, 否则o = {},此处o相当于上段代码中的per
    setmetatable(o, self)	-- 将Person设为表o的原表
    self.__index = self		-- 将Person的__index指向它本身,使得上一步相当于setmetatable(o, {__index = self})
    return o
end
-- cry方法
function Person:cry()
    print(self.name, "crying... @.@")
end

-- 通过Person类创建两个对象
-- 有初始值的对象
xiaohua = Person:new({name = "小花", gender = "M"})
-- 无初始值的对象
xiaoming = Person:new()

print(xiaohua.name, xiaohua.gender, xiaohua.age)	-->小花	M	0
xiaohua:cry()						-->小花	crying... @.@

print(xiaoming.name, xiaoming.gender, xiaoming.age)	-->小明	F	0
xiaoming:cry()						-->小明	crying... @.@
  • 定义Student类
-- 定义一个Student类,以及构造方法new()和study()方法
Student = {}
function Student:new(o)
    o = o or {}
    setmetatable(o, self)
    self.__index = self
    return o
end

function Student:study()
    print(self.name, "do a good job !!! ")
end

-- 目前为止,Student和Person是两个没啥关系的类
-- 下面介绍如何让Student构造的对象拥有Person的属性和方法
  • 使Studnet继承自Person
-- 1、将Person设置为Student的原表
setmetatable(Student, Person)
-- 2、保证Student:new(o)的参数o是Person初始化的对象,将Student:new()方法做如下修改
function Student:new(o)
    -- 此处要保证o为继承自Person的table对象
    o = Person:new(o)
    setmetatable(o, self)
    self.__index = self
    return o
end

-- 通过上述修改,Student的父类就是Person了

-- 欢快的通过Student创建对象试试吧
stu1 = Student:new()
stu2 = Student:new({name = "李华", score = "99", class = "三年级"})

print(stu1.name)	--> 小明
stu1:cry()		--> 小明	crying... @.@
stu1:study()		--> 小明	do a good job !!!

print(stu2.name, stu2.score, stu2.class)	--> 李华	99	三年级
stu2:cry()					--> 李华	crying... @.@
stu2:study()					--> 李华	do a good job !!!
  • 总结

1、在lua中,类和对象的本质都是lua table,作为类使用的table可以叫做类(类对象),通过类的构造方法得到的table叫做对象,它继承了类的所有属性和方法(域)。
2、我们通过指定metatable__index的方式人为的制造table之间的继承关系

关于metatable和__index

  • metatable:元表,其中包含一些key以及对应的函数地址,我们可以通过修改这些key对应的方法来改变table的行为,此处主要是为了提供__index指向,不提供表中自定义方法的调用
  • __index:元方法,当一个table对象访问自身不存在的方法(域)时,会尝试通过其元表的__index方法寻找解决方案,如果__index指向一个table,则会尝试在此table中访问该域,以此类推,形成一条继承链。如果__index不存在,则返回nil,如果__index指向一个方法,则将这个tablekey作为参数交给该方法处理
-- e.g.
Test = {}
function Test:new(o)
    o = o or {}
    setmetatable(o, self)
     -- 方式1
    --self.__index = self
     -- 方式2
    --self.__index = function(tab, key)
    --    print(tab, key)
    --    return self[key]
    --end
    ---- 方式3
    self.__index = function(tab, key)
        print(tab, key)
    end
    return o
end

function Test:cry()
    print("xxx")
end

t = Test:new()
print(t)
t:cry()

-- 方式1,正常访问
table: 0x7f82a4d07d30
xxx

-- 方式2,正常访问
table: 0x7ff3e4c09020
table: 0x7ff3e4c09020	cry
xxx

-- 方式3,异常访问
table: 0x7fc311409020
table: 0x7fc311409020	cry
lua: first.lua:119: attempt to call method 'cry' (a nil value)
stack traceback:
	first.lua:119: in main chunk
	[C]: ?

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值