0Pricing
Lua Academy · Урок

Вызов методов родителя с super

Явно вызывайте методы базового класса для совместной инициализации.

«Вызов методов родителя с super» — бесплатный урок Lua Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Lua Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Lua Academy содержит 4 уроков всего.

Зачем нужны вызовы родительских методов

Когда дочерний класс переопределяет метод родителя, но ему всё ещё нужна логика родителя, он явно вызывает родительский метод. В Lua нет ключевого слова super — на таблицу родителя ссылаются напрямую: Parent.method(self, args).

local Base={}
Base.__index=Base
function Base:describe()
  return "Base[name="..self.name.."]"
end

local Child={}
Child.__index=Child
setmetatable(Child,{__index=Base})

function Child:describe()
  local parentDesc = Base.describe(self)  -- super call
  return parentDesc .. " + Child[extra=true]"
end

local c=setmetatable({name="X"},Child)
print(c:describe())

Вызов родителя в конструкторе

Конструкторы дочерних классов вызывают конструкторы родителей через Parent.new() или Parent._init(self,...). Это гарантирует выполнение инициализации родителя для каждого экземпляра дочернего класса.

local Animal={}
Animal.__index=Animal
function Animal._init(self,name,sound)
  self.name=name; self.sound=sound; self.alive=true
end

local Dog={}
Dog.__index=Dog; setmetatable(Dog,{__index=Animal})
function Dog.new(name,breed)
  local self=setmetatable({},Dog)
  Animal._init(self,name,"Woof")  -- super init
  self.breed=breed
  return self
end

local d=Dog.new("Rex","Lab")
print(d.name,d.sound,d.breed)

Кооперативная инициализация

В глубоких иерархиях каждый уровень инициализирует только собственные поля и вызывает init родителя. Это оставляет каждому классу ответственность только за его собственные поля.

local A={}
function A._init(self,x) self.x=x end

local B={}
function B._init(self,x,y) A._init(self,x); self.y=y end

local C={}
C.__index=C
function C.new(x,y,z)
  local self=setmetatable({},C)
  B._init(self,x,y)
  self.z=z
  return self
end

local c=C.new(1,2,3)
print(c.x,c.y,c.z)  -- 1 2 3

Обёртка super

Создайте вспомогательную функцию super(self), возвращающую прокси-объект, который вызывает методы родителя с self. Это даёт более удобный синтаксис, чем Parent.method(self, ...).

local function super(self)
  local mt = getmetatable(getmetatable(self).__index)
  if mt then
    return setmetatable({}, {__index=function(_,k)
      local parentCls = mt.__index or mt
      return function(...) return parentCls[k](self,...) end
    end})
  end
end
print("super() helper pattern shown")

Несколько уровней

Если уровней наследования несколько, каждый уровень вызывает своего непосредственного родителя. Цепочка распространяется автоматически.

local L1={} L1.__index=L1
function L1:intro() return "L1" end

local L2={} L2.__index=L2
setmetatable(L2,{__index=L1})
function L2:intro() return L1.intro(self).."+L2" end

local L3={} L3.__index=L3
setmetatable(L3,{__index=L2})
function L3:intro() return L2.intro(self).."+L3" end

local obj=setmetatable({},L3)
print(obj:intro())  -- L1+L2+L3

Расширение метода

Расширьте метод родителя: вызовите родительскую версию, а затем добавьте дополнительное поведение. Это советы «до» или «после» без формальной платформы AOP.

local Logger={} Logger.__index=Logger
function Logger:log(msg) print("[LOG] "..msg) end

local TimedLogger={} TimedLogger.__index=TimedLogger
setmetatable(TimedLogger,{__index=Logger})

function TimedLogger:log(msg)
  local ts=os.date("%H:%M:%S")
  Logger.log(self,"["..ts.."] "..msg)  -- augment
end

local tl=setmetatable({},TimedLogger)
tl:log("Server started")

Как избежать проблем с вызовами родителя

Для вызовов родительских методов всегда используйте точное имя родительского класса, а не getmetatable(self).__index: поиск через метатаблицу может вернуть промежуточный класс, а не настоящего родителя. Явность повышает понятность и корректность кода.

-- Correct: explicit parent reference
function Child:init(x)
  Base.init(self, x)  -- explicit, clear
end

-- Fragile: uses metatable lookup
function Child:initBad(x)
  local parent = getmetatable(getmetatable(self).__index)
  -- This may not be Base if hierarchy changes!
end
print("Be explicit with parent class references")

Вызов родителя для __tostring

Переопределите __tostring в дочернем классе, включив представление родителя для получения полного описания.

local Base={}
Base.__index=Base
Base.__tostring=function(self) return "Base("..self.name..")" end

local Child={}
Child.__index=Child
setmetatable(Child,{__index=Base})
Child.__tostring=function(self)
  local baseStr = Base.__tostring(self)
  return baseStr.." + Child(level="..self.level..")"
end

local c=setmetatable({name="X",level=5},Child)
print(tostring(c))  -- Base(X) + Child(level=5)

Защищённый шаблонный метод

Шаблонный метод: базовый класс определяет каркас алгоритма с вызовами абстрактных шагов, а дочерние классы реализуют эти шаги.

local Processor={} Processor.__index=Processor
function Processor:run(data)
  data = self:preProcess(data)
  data = self:process(data)
  return self:postProcess(data)
end
function Processor:preProcess(d) return d end
function Processor:postProcess(d) return d end
function Processor:process(d) error("implement process()") end

local Upper={} Upper.__index=Upper
setmetatable(Upper,{__index=Processor})
function Upper:process(d) return d:upper() end

local p=setmetatable({},Upper)
print(p:run("hello"))  -- HELLO

Соглашение о вызове родителя

Соглашение: добавляйте префикс _ к внутренним функциям инициализации (например, _init), а публичный new() предоставляйте только в конструкторе верхнего уровня. Это сохраняет цепочку наследования чистой.

-- Convention summary:
-- Animal._init(self, ...)  -- used for super calls
-- Dog.new(...)             -- only public constructor
-- Never call Dog._init from outside

local Foo={} Foo.__index=Foo
function Foo._init(self,x) self.x=x end
function Foo.new(x)
  return setmetatable({},Foo):_init(x) or
    (function() local s=setmetatable({},Foo); Foo._init(s,x); return s end)()
end
print("Convention: _init for super, new() for public")

Вопрос о вызове родителя

Как вызвать родительский метод в Lua?

Итоги: вызовы родительских методов

Всегда вызывайте методы родителя через явную ссылку на класс: Parent.method(self, ...). Используйте соглашение _init для кооперативных конструкторов на разных уровнях наследования.

Часто задаваемые вопросы

Урок «Вызов методов родителя с super» бесплатный?

Да — полный текст урока «Вызов методов родителя с super» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Lua Academy, подпишись на CoddyKit PRO. Курс Lua Academy содержит 4 уроков всего.

Чему я научусь в уроке «Вызов методов родителя с super»?

Явно вызывайте методы базового класса для совместной инициализации. Ты практикуешь Lua Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Lua Academy?

Предыдущий опыт не требуется. Lua Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.

Сколько времени занимает урок «Вызов методов родителя с super»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Lua Academy?

Да. Каждый урок Lua Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Одиночное наследование через цепочку __index
  2. Вызов методов родителя с super
  3. Шаблоны примесей
  4. Переопределение и полиморфизм
← Назад к Lua Academy