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, muitas vezes você quer 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 o código, você pode chamar diretamente o construtor da classe pai.

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

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)                    -- Religa a 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 específico do filho brand. Por fim, alteramos a metatabela de Vehicle para Car para que a instância procure primeiro os métodos na classe filha.

Você também pode usar a sintaxe de dois-pontos ao chamar o construtor pai: Vehicle:new(speed) é equivalente a Vehicle.new(Vehicle, speed), pois ambas passam Vehicle como o primeiro argumento. As duas formas funcionam corretamente aqui, então sinta-se à vontade para usar a que considerar 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 fica no pai, enquanto cada filho lida apenas com seus atributos exclusivos.

challenge icon

Desafio

Fácil

Vamos construir uma hierarquia de criaturas em que uma classe filha estende o construtor da classe pai! Você criará uma classe pai Animal e uma classe filha Bird, na qual o construtor de Bird chama o construtor de Animal para cuidar da 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 armazene o nome do animal. Inclua um método :describe() que imprima o nome do animal. Configure o padrão de classe com __index e retorne a classe.
  • Bird.lua: Defina sua classe filha que herda de Animal. O construtor :new(name, wingspan) de Bird deve chamar o construtor da classe pai usando Animal.new(Animal, name) para inicializar o nome; em seguida, adicione o campo wingspan ao objeto e, por fim, vincule novamente a metatabela a Bird. Inclua um método :info() que imprima o nome e a envergadura em um formato específico.
  • main.lua: Carregue 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 em conjunto.

Você receberá duas entradas:

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

Em 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 deverá ser:

Animal: Eagle
Eagle has a wingspan of 200

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

Experimente você mesmo

-- main.lua: Ponto de entrada

local Bird = require('Bird')

-- Ler entradas
local name = io.read()
local wingspan = tonumber(io.read())

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

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

-- TODO: Chame :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

Pratique por conta própria: Compilador de Lua online