0Pricing
Lua Academy · Lección

Sobrescritura y polimorfismo

Sobrescriba métodos de la clase principal y consiga despacho polimórfico en tiempo de ejecución.

Sobrescritura y polimorfismo es una lección gratuita de Lua Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Lua Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Lua Academy incluye 4 lecciones en total.

Sobrescritura de métodos

Una clase hija sobrescribe un método de la clase padre definiendo un método con el mismo nombre. Cuando se llama desde una instancia hija, se ejecuta la versión de la hija. La versión del padre sigue estando disponible mediante Parent.method(self).

local Shape={} Shape.__index=Shape
function Shape:area() return 0 end
function Shape:describe() print(type(self).." area="..self:area()) end

local Circle={} Circle.__index=Circle
setmetatable(Circle,{__index=Shape})
function Circle.new(r) return setmetatable({r=r},Circle) end
function Circle:area() return math.pi*self.r^2 end

local Square={} Square.__index=Square
setmetatable(Square,{__index=Shape})
function Square.new(s) return setmetatable({s=s},Square) end
function Square:area() return self.s^2 end

Circle.new(5):describe()
Square.new(4):describe()

Despacho polimórfico

El polimorfismo permite que distintos tipos de objetos respondan de forma diferente al mismo mensaje. Una función que acepta cualquier «forma» y llama a :area() funciona con cualquier tipo de forma; cada uno responde con su propia implementación.

local shapes={
  Circle.new(3),
  Square.new(4),
  Circle.new(1),
}

local total=0
for _,shape in ipairs(shapes) do
  total=total+shape:area()
end
print(string.format("Total area: %.2f",total))

Tipado pato

Lua utiliza tipado pato: si un objeto tiene el método, funciona. No hace falta declarar una interfaz formal. Una función que llama a :speak() funciona con cualquier objeto que tenga un método speak, independientemente de su clase.

local function makeNoise(obj)
  if type(obj.speak)=="function" then
    obj:speak()
  else
    print("(silent)")
  end
end

local Duck={speak=function(self) print("Quack!") end}
local Robot={speak=function(self) print("Beep boop!") end}
local Rock={}

makeNoise(Duck)   -- Quack!
makeNoise(Robot)  -- Beep boop!
makeNoise(Rock)   -- (silent)

Polimorfismo de operadores

Los metamétodos como __add permiten el polimorfismo de operadores. Distintos tipos pueden responder a + con su propia semántica siempre que definan __add.

local Vec2={} Vec2.__index=Vec2
Vec2.__add=function(a,b) return Vec2.new(a.x+b.x,a.y+b.y) end
Vec2.__tostring=function(v) return "("..v.x..","..v.y..")" end
function Vec2.new(x,y) return setmetatable({x=x,y=y},Vec2) end

local Color={} Color.__index=Color
Color.__add=function(a,b)
  return Color.new(math.min(255,a.r+b.r),math.min(255,a.g+b.g),math.min(255,a.b+b.b))
end
function Color.new(r,g,b) return setmetatable({r=r,g=g,b=b},Color) end

print(tostring(Vec2.new(1,2)+Vec2.new(3,4)))  -- (4,6)

Patrón Visitor

El patrón Visitor separa las operaciones de los objetos. Una operación «visita» objetos de distintos tipos y llama al método adecuado según el tipo. Úselo para operaciones que deben variar según el tipo sin modificar los tipos.

local function printInfo(obj)
  local mt = getmetatable(obj)
  if mt == Circle then
    print(string.format("Circle r=%.1f area=%.2f",obj.r,obj:area()))
  elseif mt == Square then
    print(string.format("Square s=%.1f area=%.2f",obj.s,obj:area()))
  end
end
for _,s in ipairs({Circle.new(3),Square.new(4)}) do
  printInfo(s)
end

Tabla de interfaz

Defina una interfaz como una tabla de nombres de métodos. Valide que un objeto implemente todos los métodos requeridos antes de usarlo de forma polimórfica.

local function implements(obj, interface)
  for _, method in ipairs(interface) do
    if type(obj[method]) ~= "function" then
      return false, "missing: "..method
    end
  end
  return true
end

local Drawable = {"draw","resize","move"}

local Widget = {
  draw=function(self) print("draw "..self.type) end,
  resize=function(self,w,h) self.w,self.h=w,h end,
  move=function(self,x,y) self.x,self.y=x,y end,
  type="button"
}

local ok,err = implements(Widget,Drawable)
print(ok,err)  -- true nil

Comprobación de existencia de un método

Antes de llamar de forma polimórfica a un método opcional, compruebe si el objeto lo tiene. Esto permite capacidades opcionales sin exigir una clase base común.

local function maybeUpdate(obj, dt)
  if type(obj.update)=="function" then
    obj:update(dt)
  end
end

local objects={
  {x=0,y=0,update=function(self,dt) self.x=self.x+10*dt end},
  {x=0,y=0},  -- no update
  {x=0,y=0,update=function(self,dt) self.y=self.y+5*dt end},
}

for _,o in ipairs(objects) do maybeUpdate(o,1) end
for _,o in ipairs(objects) do print(o.x,o.y) end

Tabla de despacho basada en tipos

En lugar de encadenar condiciones if/elseif, use una tabla de despacho: asigne nombres de tipos a funciones controladoras. Este es el patrón de polimorfismo basado en tablas.

local handlers={
  number  = function(v) return "num:"..v end,
  string  = function(v) return "str:\"".."..v.."\"" end,
  boolean = function(v) return "bool:"..(v and "T" or "F") end,
  table   = function(v) return "tbl:#"..tostring(#v) end,
}

local function describe(v)
  local h=handlers[type(v)]
  return h and h(v) or "unknown"
end

print(describe(42))
print(describe("hello"))
print(describe({1,2,3}))

Retornos covariantes

Los métodos de las clases hijas pueden devolver tipos más específicos que los métodos de las clases padre (retorno covariante). Como Lua tiene tipado dinámico, esto resulta natural: la factoría de una clase hija devuelve una instancia hija, no solo una instancia padre.

local Base={} Base.__index=Base
function Base.new() return setmetatable({type="base"},Base) end
function Base:copy() return Base.new() end

local Child={} Child.__index=Child
setmetatable(Child,{__index=Base})
function Child.new(extra)
  local self=setmetatable({type="child"},Child)
  self.extra=extra; return self
end
function Child:copy() return Child.new(self.extra) end  -- covariant

local c=Child.new("hello")
local c2=c:copy()
print(c2.extra,getmetatable(c2)==Child)  -- hello true

Resumen del polimorfismo

El polimorfismo en Lua en la práctica consiste en usar el mismo nombre de método con un comportamiento diferente según el tipo. Se consigue mediante OOP basada en metatablas, comprobaciones de tipado pato o tablas de despacho. No hace falta un sistema formal de interfaces, solo convenciones coherentes para los nombres de métodos.

-- Three ways to achieve polymorphism:
-- 1. Metatable inheritance + method override
-- 2. Duck typing: just call it if it exists
-- 3. Dispatch table: map type -> handler

local function area(shape)
  -- Duck typing approach:
  assert(type(shape.area)=="function","needs area()")
  return shape:area()
end

print(area({area=function() return 16 end}))  -- 16

Pregunta sobre polimorfismo

¿Cómo funciona el polimorfismo en Lua?

Repaso: sobrescritura y polimorfismo

Sobrescriba los métodos de la clase padre redefiniéndolos en la clase hija. Lua resuelve las llamadas desde abajo hacia arriba mediante la cadena __index, lo que permite un despacho polimórfico natural en tiempo de ejecución.

Preguntas frecuentes

¿La lección «Sobrescritura y polimorfismo» es gratis?

Sí — el texto completo de «Sobrescritura y polimorfismo» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Lua Academy, actualiza a CoddyKit PRO. El curso de Lua Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Sobrescritura y polimorfismo»?

Sobrescriba métodos de la clase principal y consiga despacho polimórfico en tiempo de ejecución. Practicas Lua Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Lua Academy?

No se requiere experiencia previa. Lua Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.

¿Cuánto tiempo toma la lección «Sobrescritura y polimorfismo»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Lua Academy?

Sí. Cada lección de Lua Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Herencia simple con encadenamiento de __index
  2. Llamada a métodos de la clase principal con super
  3. Patrones mixin
  4. Sobrescritura y polimorfismo
← Volver a Lua Academy