- 最简单的继承
-- 创建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
不存在,则返回ni
l,如果__inde
x指向一个方法,则将这个table
和key
作为参数交给该方法处理
-- 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]: ?