Menu
Coddy logo textTech

Наследование методов

Часть раздела Object Oriented Programming путешествия по Lua на Coddy — урок 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.

Вы организуете свой код в трех файлах:

  • 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, где и находит метод. Это и есть наследование в действии!

Шпаргалка

Экземпляры дочернего класса автоматически получают доступ ко всем родительским методам через цепочку поиска Lua. Когда метод вызывается у экземпляра, Lua ищет его в каждой связанной таблице, пока не найдет.

Настройка наследования

Определение родительского класса:

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})

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

Использование унаследованных методов

Дочерние экземпляры могут вызывать родительские методы, даже если они не определены в дочернем классе:

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

Цепочка поиска: Lua проверяет buddyDogAnimal, пока метод не будет найден.

Организация классов в нескольких файлах

Файл родительского класса (Animal.lua):

local Animal = {}
Animal.__index = Animal

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

function Animal:speak()
    print(self.name .. " makes a sound")
end

return Animal

Файл дочернего класса (Dog.lua):

local Animal = require("Animal")

local Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})

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

return Dog

Использование в основном файле:

local Dog = require("Dog")
local buddy = Dog:new("Buddy")
buddy:speak()  -- Output: Buddy makes a sound

Попробуйте сами

-- main.lua: Точка входа

local Dog = require('Dog')

-- Считать имя собаки из ввода
local name = io.read()

-- TODO: Создать экземпляр Dog с заданным именем

-- TODO: Вызвать метод :speak() у экземпляра собаки
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Object Oriented Programming