Настройка наследования
Часть раздела Object Oriented Programming путешествия по Lua на Coddy — урок 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.
Цепочка поиска работает следующим образом: instance → Dog → Animal. На каждом этапе используется __index для поиска следующей таблицы. Это позволяет дочерним классам автоматически наследовать все методы родителя без их копирования.
Задание
ЛегкоДавайте построим вашу первую иерархию наследования! Вы создадите простую связь между родительским и дочерним классами, где класс Machine служит базовым, а класс Robot наследуется от него.
Вы организуете свой код в трех файлах:
Machine.lua: Определите родительский класс, используя стандартный паттерн классов. Включите конструктор:new()и метод:status(), который выводитMachine is operational. Не забудьте настроить__indexи вернуть класс в конце файла.Robot.lua: Определите дочерний класс, который наследуется от Machine. Подключите модуль Machine, настройте таблицу Robot с ее собственным__indexи установите связь наследования с помощьюsetmetatable(Robot, {__index = Machine}). Включите конструктор:new(), который создает экземпляр с Robot в качестве метатаблицы.main.lua: Соберите все вместе, подключив модуль Robot, создав экземпляр Robot и вызвав унаследованный метод:status().
Ключевая концепция здесь заключается в том, что класс Robot сам не определяет :status() — он наследует этот метод от Machine через цепочку метатаблиц. Когда вы вызываете :status() у экземпляра Robot, Lua сначала ищет его в Robot, не находит, а затем переходит по ссылке __index к Machine, где и обнаруживает метод.
Ваш вывод должен быть:
Machine is operationalЭта единственная строка доказывает, что наследование работает — ваш Robot успешно получил доступ к методу, определенному только в его родительском классе!
Шпаргалка
Чтобы создать наследование в 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 автоматически получать доступ к методам Animal.
Цепочка поиска выглядит следующим образом: экземпляр → Дочерний класс → Родительский класс. На каждом этапе используется __index для поиска следующей таблицы.
Попробуйте сами
-- main.lua: Собираем всё вместе
-- TODO: Подключите модуль Robot
-- TODO: Создайте экземпляр Robot, используя Robot:new()
-- TODO: Вызовите унаследованный метод :status() для вашего экземпляра робота
-- Это должно вывести "Machine is operational"
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Object Oriented Programming
1Концепция 'self'
Таблицы с функциямиЯвный 'self'Синтаксис с двоеточиемТочка против двоеточияИтоги — Движущаяся точка4Проект: Цифровой банк
Настройка проектаМетод пополнения7Полиморфизм и переопределение
Переопределение методовВызов родительских методовУтиная типизацияОбщий интерфейсПроверка типаИтоги — Роли сотрудников2Паттерн прототипа класса
Концепция прототипаСвязывание через __indexКонструктор :new()Инициализация атрибутовНезависимые экземплярыИтоги — Автозавод5Перегрузка операторов в ООП
Сложение объектовВычитание объектовКонкатенация объектовСравнение объектов (<, >)Повторение — Математика кошелька8Инкапсуляция
Соглашения об именованииЗамыкания для приватностиДоступ через замыканияТаблицы только для чтенияЛогика валидацииИтоги — Защищенное хранилище11Паттерны проектирования (Lite)
Фабричные функцииТаблица SingletonПаттерн IteratorObserver (Слушатель)Итоги — Logger Factory3Состояние и поведение объектов
Переменные экземпляраГеттерыСеттерыВычисляемые свойстваФорматирование строкПроверка на равенствоПовторение — Оценка студента6Основы наследования
Настройка наследованияНаследование методовРасширение конструктораДобавление дочерних методовОбщее и уникальноеИтоги: Иерархия фигур