设置继承
本课属于 Coddy Lua 学习旅程的“面向对象编程”单元。第 31 课,共 70 课。
到目前为止,你已经创建了这样的类:每个对象都会在一个原型表中查找方法。但如果你想让一个类基于另一个类构建,该怎么办?这时就要用到继承:子类可以访问父类中的所有内容,同时添加自己的功能。
关键点在于,类表本身也可以有元表。当 Lua 在子类中找不到某个内容时,会查看子类元表的 __index,它指向父类。
-- 父类
local Animal = {}
Animal.__index = Animal
function Animal:new()
local obj = {}
setmetatable(obj, Animal)
return obj
end
function Animal:breathe()
print("Breathing...")
end现在来看看继承的设置。我们创建一个子类,并将它的元表设置为查找父类:
-- 子类
local Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})这一行代码 setmetatable(Dog, {__index = Animal}) 创建了继承关系。当 Dog 实例调用一个在 Dog 中找不到的方法时,Lua 会检查 Animal。
查找链的工作方式如下:实例 → Dog → Animal。每一步都会使用 __index 查找下一个要搜索的表。这样,子类无需复制父类的方法,就能自动继承所有父类方法。
挑战
简单来构建你的第一个继承层次结构吧!你将创建一个简单的父类与子类关系,其中 Machine 类作为基类,Robot 类继承自它。
你将把代码分成三个文件:
Machine.lua:使用标准的类模式定义父类。添加一个:new()构造函数和一个会打印Machine is operational的:status()方法。别忘了设置__index,并在文件末尾返回这个类。Robot.lua:定义继承自 Machine 的子类。引入 Machine 模块,设置 Robot 表及其自己的__index,并使用setmetatable(Robot, {__index = Machine})建立继承关系。添加一个:new()构造函数,用 Robot 作为元表创建实例。main.lua:通过引入 Robot 模块、创建 Robot 实例并调用继承来的:status()方法,把所有内容串联起来。
这里的关键概念是,Robot 类本身没有定义 :status()。它通过元表链继承了 Machine 的这个方法。当你在 Robot 实例上调用 :status() 时,Lua 会先在 Robot 中查找。如果没找到,就会沿着 __index 链接找到 Machine,并在那里找到这个方法。
你的输出应该是:
Machine is operational这一行就能证明继承正常工作。Robot 成功调用了只在父类中定义的方法!
亲手试试
-- main.lua:把所有内容整合起来
-- TODO:加载 Robot 模块
-- TODO:使用 Robot:new() 创建一个 Robot 实例
-- TODO:在你的机器人实例上调用继承的 :status() 方法
-- 这应该会打印“Machine is operational”
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Lua 在线编译器