Menu
CoddyTech

继承方法

本课属于 Coddy Lua 学习旅程的“面向对象编程”单元。第 32 课,共 70 课。

建立继承关系后,子类实例会自动获得对所有父类方法的访问权限。这是通过 Lua 的查找链实现的:你在实例上调用方法时,Lua 会依次搜索各个关联的表,直到找到你要查找的内容。

考虑这样一种设置,其中 Animal 定义了一个 :breathe() 方法:

local Animal = {}
Animal.__index = Animal

function Animal:new()
    local obj = {}
    setmetatable(obj, Animal)
    return obj
end

function Animal:breathe()
    print("Breathing...")
end

-- Dog 继承自 Animal
local Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})

function Dog:new()
    local obj = {}
    setmetatable(obj, Dog)
    return obj
end

现在看看创建一个 Dog 并调用父类方法时会发生什么:

local buddy = Dog:new()
buddy:breathe()  -- 输出:Breathing...

Dog 类从未定义 :breathe(),但它仍然可以正常工作。Lua 会先检查 buddy,没有找到,然后检查 Dog,仍然没有找到,最后在 Animal 中找到了它。这种自动继承方法的机制意味着,你只需在父类中编写一次共享行为,所有子类就能立即受益。

challenge icon

挑战

简单

让我们构建一个简单的动物层次结构,看看方法继承如何发挥作用!你将创建一个 Animal 父类和一个 Dog 子类,然后演示 Dog 实例可以使用只在 Animal 中定义的方法。

你将把代码分成 3 个文件:

  • Animal.lua:使用标准的类模式定义父类。添加一个 :new(name) 构造函数,用来保存动物的名字;再添加一个 :speak() 方法,输出动物的名字,后面跟着 makes a sound。在文件末尾返回这个类。
  • Dog.lua:定义继承自 Animal 的子类。引入 Animal 模块,并设置继承关系,让 Dog 可以访问 Animal 的方法。添加一个 :new(name) 构造函数,用来保存名字并将 Dog 设置为元表。Dog 类不应该定义自己的 :speak() 方法,而是继承 Animal 中的这个方法。
  • main.lua:引入 Dog 模块,从输入中读取一个名字,用这个名字创建一个 Dog 实例,并对它调用 :speak() 方法。

你将收到一个输入:狗的名字。

例如,如果输入是 Buddy,输出应该是:

Buddy makes a sound

这里的关键是,Dog 类从未定义 :speak(),但对 Dog 实例调用它却能正常工作。Lua 会沿着查找链,从 Dog 实例到 Dog 类,再到找到该方法的 Animal 类。这就是继承的作用!

亲手试试

-- main.lua:入口文件

local Dog = require('Dog')

-- 从输入中读取狗的名字
local name = io.read()

-- TODO:用给定的名字创建一个 Dog 实例

-- TODO:调用 Dog 实例的 :speak() 方法
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Lua 在线编译器