Dědičnost

Jabloň je taky plodina: roste den po dni a dá se popsat jako každá jiná plodina. Má ale něco navíc: dává ovoce. Mohli byste celou třídu Plodina zkopírovat a doplnit, jenže pak byste každou změnu plodin museli dělat dvakrát. Místo toho může třída dědit od jiné třídy: dostane všechny její metody, přidá vlastní a ty, které mají fungovat jinak, nahradí:

local Plodina = {}
Plodina.__index = Plodina

function Plodina.new(nazev, dny)
    local plodina = {nazev = nazev, dny = dny, vek = 0}
    setmetatable(plodina, Plodina)
    return plodina
end

function Plodina:dalsiDen()
    self.vek = self.vek + 1
end

function Plodina:popis()
    return self.nazev .. ", den " .. self.vek .. "/" .. self.dny
end

local Strom = {}
Strom.__index = Strom
setmetatable(Strom, {__index = Plodina})

function Strom.new(nazev, dny, ovoce)
    local strom = Plodina.new(nazev, dny)
    setmetatable(strom, Strom)
    strom.ovoce = ovoce
    return strom
end

function Strom:popis()
    return Plodina.popis(self) .. ", dává " .. self.ovoce
end

local psenice = Plodina.new("Pšenice", 2)
local jablon = Strom.new("Jabloň", 30, "jablka")
psenice:dalsiDen()
jablon:dalsiDen()
print(psenice:popis())
print(jablon:popis())

Vypíše:

Pšenice, den 1/2
Jabloň, den 1/30, dává jablka

Co je nového:

  • local Strom = {} a Strom.__index = Strom udělají z tabulky Strom třídu, stejně jako u třídy Plodina.
  • setmetatable(Strom, {__index = Plodina}) dá metatabulku samotné třídě Strom: co Strom nemá, hledá Lua ve třídě Plodina. Tenhle řádek je ta dědičnost. Strom je odvozená třída (podtřída) třídy Plodina a Plodina je jeho rodičovská třída.
  • Strom.new neopakuje, co dělá Plodina.new. Zavolá Plodina.new, aby vznikla plodina s názvem, dny a stářím, potom z ní pomocí setmetatable(strom, Strom) udělá strom (tabulka má jen jednu metatabulku, takže tím nahradí třídu Plodina) a přidá stromu jeho vlastní klíč ovoce.

Když zavoláte jablon:dalsiDen(), hledá Lua dalsiDen krok za krokem: v samotné tabulce jablon (není), přes metatabulku jabloně ve třídě Strom (není) a přes metatabulku třídy Strom ve třídě Plodina (je). Je to řetěz: jablon → Strom → Plodina.

Přepsání metody. Strom má vlastní popis. Lua přestane hledat, jakmile nějakou metodu popis najde, a u stromu ji najde nejdřív ve třídě Strom. Tahle metoda tedy nahradí (přepíše, anglicky override) metodu ze třídy Plodina. Pšenice je obyčejná plodina, a tak dál používá popis ze třídy Plodina. Verze stromu nemusí opakovat práci rodiče: Plodina.popis(self) zavolá metodu rodiče na stejném stromu. Všimněte si tečky a ručně předaného self. self:popis() by znovu zavolalo metodu popis stromu, která by volala sama sebe pořád dokola, dokud by program neskončil chybou stack overflow (přetečení zásobníku).

Typické chyby:

  • Zapomenuté setmetatable(Strom, {__index = Plodina}): stromy nenajdou metody plodin a jablon:dalsiDen() skončí chybou attempt to call a nil value (method 'dalsiDen').
  • Zapomenuté setmetatable(strom, Strom) ve Strom.new: nový strom zůstane obyčejnou plodinou. jablon:popis() pak použije verzi ze třídy Plodina, o ovoci nic neřekne a vlastní metody stromu se nenajdou.
  • Očekávání, že se zdědí i metametody. __tostring, __lt, __add a ostatní hledá Lua přímo v metatabulce objektu, ne přes __index. Když má Plodina metametodu __tostring, stromy se pořád vypisují jako table: 0x…, dokud nepřidáte Strom.__tostring = Plodina.__tostring.

Pokyny

Pod metodou Zvire:mluv založte třídu Krava, která dědí od třídy Zvire: vytvořte tabulku, nastavte její __index a dejte jí metatabulku, jejíž __index je Zvire.

Přidejte konstruktor Krava.new(jmeno). Ten vytvoří zvíře pomocí Zvire.new se zvukem "bú", pomocí setmetatable z něj udělá krávu, přidá klíč mleko s hodnotou 0 a krávu vrátí. Přidejte i metodu Krava:dejMleko(litry), která k mleko přičte litry. Na konci programu vytvořte Bellu pomocí Krava.new("Bella"), nechte ji dát 8 litrů mléka a potom 6 a vypište, co dělá. Program vypíše:

Rex dělá haf
Bella dělá bú

Přepište pro krávy metodu mluv: Krava:mluv() vrátí to, co vrací Zvire.mluv, a za tím, kolik mléka kráva dala. Rex je obyčejné zvíře, a tak dál jen dělá haf. Program vypíše:

Rex dělá haf
Bella dělá bú a dala 14 litrů mléka

Začněte programovat zdarma

Registrací souhlasíte s provozními podmínkami a zásadami ochrany osobních údajů.

Nebo se registrujte pomocí:

8/9