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á jablkaCo je nového:
local Strom = {}aStrom.__index = Stromudělají z tabulkyStromtřídu, stejně jako u třídyPlodina.setmetatable(Strom, {__index = Plodina})dá metatabulku samotné tříděStrom: coStromnemá, hledá Lua ve tříděPlodina. Tenhle řádek je ta dědičnost.Stromje odvozená třída (podtřída) třídyPlodinaaPlodinaje jeho rodičovská třída.Strom.newneopakuje, 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říduPlodina) 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 ajablon:dalsiDen()skončí chybouattempt to call a nil value (method 'dalsiDen'). - Zapomenuté
setmetatable(strom, Strom)veStrom.new: nový strom zůstane obyčejnou plodinou.jablon:popis()pak použije verzi ze třídyPlodina, o ovoci nic neřekne a vlastní metody stromu se nenajdou. - Očekávání, že se zdědí i metametody.
__tostring,__lt,__adda ostatní hledá Lua přímo v metatabulce objektu, ne přes__index. Když máPlodinametametodu__tostring, stromy se pořád vypisují jakotable: 0x…, dokud nepřidáteStrom.__tostring = Plodina.__tostring.
Jak psát:
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ékaZačněte programovat zdarma
8/9