47.1 Zásobník a Fronta
47.2 Tvorba zásobníku
47.3 O objektech
47.4 Domácí úkol
47.5 V další lekci
47.1 Zásobník a Fronta
Než se pustíme do tvorby obou objektů, měli bychom si říci, co tyto objekty jsou.
Fronta – datová struktura tipu FIFO (first in first out), znamená to tedy to, že data, která do fronty jako první přijdou, z ní jako první také vystoupí. Můžeme si to představit jako nějakou frontu třeba na lístky; člověk který si do fronty stoupl jako první, z ní také jako první odejde, prvky tedy frontu opouštějí ve stejném pořadí, v jakém do ní vešly. Předbíhání zde nehrozí.
Zásobník – datová struktura tipu LIFO (last in first out), znamená to tedy to, že data, která do zásobníku přijdou až poslední, přečteme jako první. Představit si to můžeme tak, že skládáme na sebe nějaké věci po jedné a sloupek se nám navyšuje a pak je zase budeme po jednom brát.
47.2 Tvorba zásobníku
Se zásobníkem začneme z toho důvodu, že vytvořit ho je mnohem jednodušší než vytvořit frontu. Pracujeme totiž jen s jediným ukazatelem, a tudíž nám k celému objektu postačí pouhé dvě proměnné:
Dim Pointer As Long 'ukazuje na nejnižší volné místo zásobníku
Dim Data(255) As Long 'pole, které obsahuje data uložená do zásobníku
Většinu se, jak jste, doufám, pochopili, dozvíte v komentářích kódů. Proměnná pointer je z důvodu mírné úspory kódu volena ne jako ukazatel na vrchol zásobníku, ale ukazuje nad něj. Pro jistoto se zmíním o tom, co je to vrchol zásobníku. Vrchol zásobníku je místo, na němž je uložen poslední horní prvek. To znamená, že kdybychom měli zásobník, ve kterém je místo na 256 prvků, jako je tomu v našem případě, a bylo v něm 97 prvků, tak by ukazatel vrchol ukazoval na 97. prvek, tedy na 96. pozici v datovém poli (96 proto, že, jak jistě víte, pole se běžně indexují od nuly a věřte, že je to tak dobře). Ale jelikož my indexujeme až první volnou pozici pole, bude ukazatel ukazovat na pole s indexem 97.
Velikost zásobníků bývá omezená, jak jsem se již zmínil. Tento zásobník je omezen velikostí datového typu byte na 256 prvků, tedy prvky v ozmezí 0-255. Zásobník proto při zápisu musíme kontrolovat, překročením oné hodnoty by totiž mohlo dojít k pádu programu, o to se stará podmínka funkce ZapisData.
Public Function ZapisData(vstup As Long) As Long
If Pointer > 255 Then 'kontroluje, zda nechochází k přetečení a zda je možné zapsat další data
ZapisData = 1 'zapis se nezdařil
Else
Data(Pointer) = vstup 'zapisuje data na první volné místo zásobníku
Pointer = Pointer + 1 'zvyšuje hodnotu ukazatele, aby ukazoval na první volné místo
'ono první volné místo je nyní o jedno "políčko" výš.
ZapisData = 0 'data byla bez problému zapsána
End If
End Function
Funkce ZapisData, jak její název vypovídá, zapisuje data do zásobníku a skládá je pěkně na sebe. To ale není jediné, co umí. Umí také vrátit logickou hodnotu, která nám říká, jestli došlo k přetečení či nikoliv.
Při čtení dat není problém přetečením zásobníku, ale vyskytuje se zde děj úplně opačný, tomu říkáme podtečení, a vzniká, když chceme číst data, ale zásobník je prázdný. Tomuto jevu se dá zabránit stejným způsobem, jako tomu bylo u přetečení, tedy běžnou podmínkou. Hůře je o ní ale informovat, přenášet informaci ve jménu funkce není zrovna vhodné, protože v ní již přenášíme hodnotu čtenou z pole. Pokud bychom předpokládali, že v poli budou nenulové hodnoty, dá se situace vyřešit takto:
Public Function CtiData() As Long
If Pointer = 0 Then 'kontrlouje, zda nedochází k podtečení
'pokud je ukzatel prvního volného místa na 0, potom by obazené místo muselo být mínus jedna
'mínus jedničkou ovšem pole nazačíná, takže bychmo neměli odkud číst
CtiData = 0 'čtení se nezdařilo, v zásobníku nejsou žádná data
Else
Pointer = Pointer - 1 'vrátí pozici ukazatele na vrchol zásobníku
CtiData = Data(Pointer) 'přečte data a ukazatel zůstane na prvním volném místě
's ukzatelem tedy již nemusíme hýbat, hodnotu nemusíme mazat, protože následovně bude přepsána
End If
End Function
V opačném případě může řešení vypada takto:
Public Function CtiData(ByRef vystup As Long) As Long
If Pointer = 0 Then 'kontrlouje, zda nedochází k podtečení
'pokud je ukzatel prvního volného místa na 0, potom by obazené místo muselo být mínus jedna
'mínus jedničkou ovšem pole nazačíná, takže bychmo neměli odkud číst
vystup = 0
CtiData = 1 'čtení se nezdařilo, v zásobníku nejsou žádná data
Else
Pointer = Pointer - 1 'vrátí pozici ukazatele na vrchol zásobníku
vystup = Data(Pointer) 'přečte data a ukazatel zústane naprvním volném místě
's ukzatelem tedy již nemusíme hýbat, hodnotu nemusíme mazat, protože následovně bude přepsána
CtiData = 0 'čtení proběhlo bez problémů
End If
End Function
Pro přenos hodnoty tedy využijeme proměnnou. A v názvu funkce vrátíme hodnoty, která bude informovat o její úspěšnosti či neúspěšnosti. Je to také alternativa k uživatelsky definovaným datovým typům. K objektům je vhodné přiřazovat různé pomocné a podpůrné funkce, jež mohou mnohdy výrazně usnadnit práci s nimi.
Public Function GetPointer() 'vrací hodnotu ukazatele na vrchol zásobníku
GetPointer = Pointer - 1 ', tj. o jednu nižší než je náš ukazatel, na první volné místo
End Function
První z uvedených funkcí, jak vidíte, ukazuje na vrchol zásobníku. Druhá nás informuje o statusu zásobníku, a to třemi hodnotami, blíže je to posáno v komentáři.
Public Function GetStat() 'vrací stav zásobníku
Select Case Pointer
Case Is < 1
GetStat = 1 'zásobník je prázdný, data lze pouze zapisovat
Case 1 To 255
GetStat = 0 'zasobník je připrven jak pro čtení, tak pro zápis
Case Is > 255
GetStat = 2 'zásobník je plný, data lze pouze číst
End Function
Funkcí ale může být mnoho a mohou být různé a mohou vracet různé hodnoty, třeba procentuální zaplnění zásobníku nebo kdo ví co.
No, ještě než kapitolu ukončím, myslím, že by bylo záhodno napsat pár řádků ovládání objektu přes jeho interface. Prvně musíme vytvořit ze třídy objekt.
Set balicek = New zasobnik
Potom již s objektem můžeme pracovat jako s každým jiným.
Print balicek.ZapisData(Val(Text1.Text)) 'zapsání dat
Print balicek.CtiData(nevim) 'čtení dat
Print nevim 'tisk proměnné s daty
Print balicek.GetPointer 'vypsání pozice pointru
47.3 O objektech
No, to by byla, řekl bych, poněkud lepší forma výkladu objektu než v minulém díle, kde jsme to spíš nahlodávali. Ale stále to není ono. Máme sice objekt, který je funkční, ale buďme upřímní. Jak často asi takovýto objekt využijeme? Řekl bych, že spíš nikdy než někdy. Zásobník přeci jen není příliš často používán, přestože je to základní datová struktura. Jako příklad si myslím, že poslouží, ale to spíš v tom, že nám ukáže vlastnosti objektů a to, jak vypadá vnitřní struktura objektu než to, kde se používají. Dnes je stále slyšet o nějakém OOP. Ano, toto programování používá především objektů. Údajně to umožňuje programátorovi soustředit se o to více na samotné řešení problému než na kód. Já se teď pokusím to vzít ze svého pohledu.
Já jsem vyrostl na událostmi řízeném programování Visual Basicu, které mi, pro svou přehlednost a dalo by se říci i jednoduchost (rychlost vývoje aplikací), přirostlo k srdci. Ovšem VB jako takový sám o sobě využívá objekty a my s nimi také pracujeme. Ovšem jsou to objekty předdefinované (TextBox, Label, CommandButton). Já vlastnoručně psané příliš nepoužívám (i když stane se), ale na druhou stranu, využívám toho, co mi nabízí objekty předdefinované (standardní), a to tak, že na plno a dost často je využívám jako, řekněme tomu, šablony pro tvorbu svých kopií. O co jde, si řekneme o několik dílů později, když se vrhneme na aplikace v MDI.
Teď tedy ještě zpět; podíváme se na to, kde využít objektu a kde jen modulu. Objekt se vyplatí používat především tam, kde počítáme s tím, že objektů budeme používat několik, vrátil bych se k onomu, o několik řádků výše popsanému, zásobníku. Pokud tedy budu v projektu používat třeba 10 zásobníků, které do sebe mají ukládat data a být na sobě naprosto nezávislé, není lepší řešení než vytvořit si třídu a podle ní objekt jednoduše vytvořit, navíc si vytvoříte jen tolik objektů, kolik jich ve skutečnosti budete potřebovat, nemusíte tedy zaplácávat paměť tím, co nepotřebujete. Objekt je, podle mého názoru, zbytečné používat pro, řekněme, prvky, které se budou vyskytovat jednou (někdo může namítnout, že objekty a objekty a objekty, ale všeho moc škodí). Co se týče některých funkcí, tak už jsem viděl, že je jistí lidé rvou také do objektů a to je pro mě vcelku nepochopitelné. O tom, co s funkcemi, se podíváme v některém z brzkých dílů.
No a k praktickému použít se dostaneme co nevidět.
47.4 Domácí úkol
Za domácí úkol bude vytvořit objekt, a to datovou strukturu fronta. Úkol ale tentokráte nebude jen o programování, ale, pro některé z vás, i o hledání. A to proto, aby fronta fungovala tak, jak má, a neprobíhaly tam žádné zbytečné kroky navíc. Na to si dám při známkování tohoto úkolu pozor.
47.5 V další lekci
Tvorba a práce s projekty MDI (Multi-Dokument Interface). Vytvoříme si jakýkoliv program, který nám umožní otevření více souborů. A to z toho důvodu, že si ukážeme to hezké na objektech.