Menu
Coddy logo textTech

Estendendo o Construtor

Parte da seção Programação Orientada a Objetos do Journey de Lua da Coddy — lição 33 de 70.

Quando uma classe filha herda de uma classe pai, você geralmente deseja que o construtor da filha inicialize tudo o que o pai inicializaria — além de quaisquer campos adicionais específicos da filha. Em vez de duplicar código, você pode chamar o construtor da classe pai diretamente.

A técnica envolve o uso do nome da classe pai para invocar seu método :new(), passando self como o primeiro argumento. Isso cria o objeto base com toda a inicialização do pai, que você então customiza para o filho.

local Vehicle = {}
Vehicle.__index = Vehicle

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

-- Car herda de Vehicle
local Car = {}
Car.__index = Car
setmetatable(Car, {__index = Vehicle})

function Car:new(speed, brand)
    local obj = Vehicle.new(Vehicle, speed)  -- Chama o construtor pai
    obj.brand = brand                         -- Adiciona campo específico do filho
    setmetatable(obj, Car)                    -- Re-vincula ao Car
    return obj
end

Observe as etapas principais no construtor filho: primeiro, chamamos Vehicle.new(Vehicle, speed) para obter um objeto com o campo speed já definido. Em seguida, adicionamos o campo brand específico do filho. Finalmente, alteramos a metatable de Vehicle para Car para que a instância procure métodos na classe filha primeiro.

Você também pode usar a sintaxe de dois pontos ao chamar o construtor pai — Vehicle:new(speed) é equivalente a Vehicle.new(Vehicle, speed), já que ambos passam Vehicle como o primeiro argumento. Qualquer uma das formas funciona corretamente aqui, então sinta-se à vontade para usar a que achar mais legível.

local myCar = Car:new(120, "Toyota")
print(myCar.speed)  -- Saída: 120
print(myCar.brand)  -- Saída: Toyota

Este padrão mantém seu código DRY — a lógica de inicialização compartilhada reside no pai, enquanto cada filho lida apenas com seus atributos únicos.

challenge icon

Desafio

Fácil

Vamos construir uma hierarquia de criaturas onde uma classe filha estende o construtor de sua classe pai! Você criará uma classe pai Animal e uma classe filha Bird, onde o construtor de Bird chama o construtor de Animal para lidar com a inicialização compartilhada antes de adicionar seu próprio atributo exclusivo.

Você organizará seu código em três arquivos:

  • Animal.lua: Defina sua classe pai com um construtor :new(name) que armazena o nome do animal. Inclua um método :describe() que imprime o nome do animal. Configure o padrão de classe padrão com __index e retorne a classe.
  • Bird.lua: Defina sua classe filha que herda de Animal. O construtor :new(name, wingspan) do seu Bird deve chamar o construtor pai usando Animal.new(Animal, name) para inicializar o nome, depois adicionar o campo wingspan ao objeto e, finalmente, vincular novamente a metatabela ao Bird. Inclua um método :info() que imprime tanto o nome quanto a envergadura em um formato específico.
  • main.lua: Requeira seu módulo Bird, leia duas entradas (nome e envergadura), crie uma instância de Bird e chame ambos os métodos para demonstrar que a funcionalidade herdada e a específica da classe filha funcionam juntas.

Você receberá duas entradas:

  1. O nome do pássaro
  2. A envergadura do pássaro (um número)

No seu arquivo principal, crie um Bird com o nome e a envergadura fornecidos. Em seguida, chame :describe() seguido de :info() em linhas separadas.

O método :describe() (herdado de Animal) deve imprimir:

Animal: {name}

O método :info() (definido em Bird) deve imprimir:

{name} has a wingspan of {wingspan}

Por exemplo, se as entradas forem Eagle e 200, a saída deve ser:

Animal: Eagle
Eagle has a wingspan of 200

A chave aqui é que o construtor do seu Bird não duplica a inicialização do nome — ele delega esse trabalho ao construtor do Animal e, em seguida, adiciona apenas o que é exclusivo dos pássaros. Isso mantém seu código DRY enquanto constrói uma cadeia de herança adequada!

Experimente você mesmo

-- main.lua: Ponto de entrada

local Bird = require('Bird')

-- Lê as entradas
local name = io.read()
local wingspan = tonumber(io.read())

-- TODO: Criar uma instância de Bird com o name e wingspan fornecidos

-- TODO: Chamar :describe() no bird (herdado de Animal)

-- TODO: Chamar :info() no bird (definido em Bird)
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos