Procvičení neobjektových vlastností jazyka C++ 2





Pokračujte v minulém cvičení procvičení neobjektových vlastností.



U následujících bodů se předpokládá, že po implementaci funkcí/vlastností tyto použijete při volání z funkce main a zjistíte, zda-li korektně fungují. Proto je vhodné „potrápit“ funkci několika voláními (s malými čísly, velkými čísly, zápornými čísli, nulovými hodnotami a jejich kombinacemi).

Nezapomeňte na kontrolu hlášení funkce check – manipulace s pamětí musí být v pořádku.



Reference

10) Napište funkci vykonávající stejnou činnost jako AllocVector(TVector*, int), ale pro předání proměnné struktury použijte reference AllocVector(TVector &, int). Nechte v programu obě funkce. Ověřte, že je to možné, a že obě fungují. Vysvětlete rozdíly.

11) Podobně převeďte předávání parametrů do a z (ostatních) funkcí na předávání pomocí reference (tam kde to jde a dává to smysl). Předávání pomocí reference je výhodné tam, kde předáváme větší proměnné (složené proměnné struct, class takřka vždy, pokud z předávání pomocí hodnoty neplynou nějaké výhody). Dále je reference výhodná tam, kdy chceme proměnnou ve funkci změnit tak, aby se změna projevila i mimo funkci.


Konstantní parametry

12) Projděte prototypy funkcí a definice jejich parametrů. Parametry, které se v dané části programu (funkci) nemění, označte jako const. Změnu je nutné provést ve zdrojovém (u definice funkce) i v hlavičkovém souboru (u deklarace funkce).

Označování proměnných pomocí const je z programátorského hlediska důležitá dovednost. Pokud budeme důsledně dodržovat pravidlo, že proměnné, které se ve funkci neměnní jsou v hlavičce označeny const a proměnné bez tohoto kvalifikátoru se mění, usnadní nám toto velice orientaci v kódu. Pouze podle hlavičky funkce se můžeme orientovat v tom, které proměnné se ve funkci změní, a které zůstanou stejné a nemusíme „luštit“ funkce, nebo číst jejich komentáře (pokud je autor vůbec uvedl).



Rozdělení do souborů

13) Pro další práci s vytvářenými funkcemi je výhodné, aby byly ve zvláštním zdrojovém souboru (ty funkce, které k sobě logicky náleží) a příslušný hlavičkový soubor. Proto projekt rozdělíme na tak aby s funkce main byla v jednom zdrojovém souboru a sloužila jako ukázka použití funkcí a zároveň jako jejich testovací kód. Pro funkce je vhodné mít jejich kód ve zdrojovém souboru a k němu hlavičkový soubor, který tvoří interface – nebo-li uvede proměnné, které je možné používat v ostatních modulech programu.
Vytvořte soubory funkce.cpp a funkce.h. Hlavičkový soubor standardně ošetřete a přesuňte do něj:
- definici struktury
- hlavičky funkcí
- definice konstant a proměnných, které je nutné sdílet v rámci programu s ostatními moduly.
Do zdrojového souboru funkce.cpp přesuňte funkce, které souvisí s prací se strukturami (funkce main zůstane v původním souboru.)

Hlavičkový soubor přidejte (includujte) do zdrojových souborů (s main i se zdrojovými kódy knihovny pro práci s TVector).



Vytvoření struktury pro 2D pole

14) Vytvořte strukturu TPoleVect, která bude obsahovat 2D pole – v našem případě bude tedy obsahovat pole struktur typu TVector. Návrh by měl být podobný jako u TVector (naalokovaná délka, využitá délka a vlastní data – pole TVector).

15) Napište funkci, která vztvoří strukturu TPoleVect platnými daty (naalokuje místo pro struktury i jejich vnitřní prvky – pole hodnot)
AllocPoleVectoru(TPoleVect & aPole, size_t aPocetVektoru, size_t aPocetPrvkuVektoru,XX aInicializacniHodnota).
Název funkce je stejný jako již dříve vytvořená jiná funkce, pouze parametry jsou jiné. K chybě při překladu nedojde díky mechanizmu přetěžévání funkcí – v C++ může mít více funkcí stejný název pokud se jednoznačně liší parametry funkce ().

16) Napište funkci, která uvolní prvky uvnitř struktury (nejdříve pole hodnot a potom pole struktur TVector).



Funkce pro nastavení a získání hodnoty

17) Vytvořte funkce pro zadávání a čtení hodnoty z pole – tzv. gettery a settery.
Tyto funkce slouží jako mezičlánek mezi „běžným“ uživatelem a vlastní třídou. Tato koncepce návrhu, kdy se k proměnným nepřistupuje přímo, ale pomocí funkcí, umožní kontrolovat přístup do pole – funkce zkontroluje požadované parametry (zde řádku a sloupce) a pokud tyto v poli neexistují, vygeneruje výjimku. Tyto funkce budou mít jako parametr strukturu TPoleVect a pozice prvku, se kterým se má pracovat. Funkce provede kontrolu, zda pozice je uvnitř pole – pokud není, zahlásí chybu pomocí výjimky.
Pokud je prvek uvnitř pole možné vrátit referencí, můžeme jako getter a setter použít jedinou funkci. Výhodou této koncepce je jednoduchost a to, že se předávají reference (úsporné předávání parametrů). Nevýhodou je to, že nyní nedošlo k úplnému oddělení dat, protože přes referenci je možné zjistit adresy prvků pole a následně ho „napadnout“.
K úplnému oddělení dat by došlo, kdyby byly funkce dvě a getter vracel hodnotu (nebo alespoň referenci na konstantní proměnnou).

17a) Napište funkce XX Get(TPoleVect, index1, index2) a Set(TPoleVect, index1, index2, value) , kde XX je typ vkládané nebo získávané proměnné. Tyto funkce pracují s hodnotami. Uživatel nemá přístup k hodnotám pole.

17b) Jelikož nejčastěji nastavovanou hodnotou je nula, využijte pro funkci Set mechanizmus implicitních parametrů pro nastavení hodnoty value na nulu.

17c) Funkce s přímým přístupem do pole je pohodlnější, stačí jedna, ale je nebezpečnější v tom, že uživatel získá přímý přístup k prvkům – a může je tedy měnit bez kontroly funkcí interface. XX& GetRef(TPoleVect, index1, index2)
s použitím pro získání hodnoty
x = GetRef(TPoleVect, index1, index2);

a s použitím pro nastavení hodnoty

GetRef(TPoleVect, index1, index2) = 10;



Oddělení dat

18) Aby se nevytvářely kolize mezi kódy programátorů, kteří na programu spolupracují, je výhodné použít mechanizmus jmenných prostorů (NameSpace).
Vyzkoušejte umístění všech vytvořených datových struktur a funkcí do jmenného prostoru NSFunkce (v hlavičkovém i zdrojovém souboru funkcí).

19) Upravte kód s funkcí main tak, aby akceptoval změnu zařazení funkcí a struktur do jmenného prostoru.
- Začněte nejjednodušším způsobem using namespace NSFunkce – toto řešení je jednoduché ale zveřejní celý jmenný prostor a tím popře jeho hlavní funkci – oddělit použitá jména od ostatních.
- Použijte zveřejnění vybraných prvků (proměnné, funkce, hodnoty) pomocí using NSFunkce::funkce ale u některých si zkuste i přímý přístup v kódu pomocí celého jména (název prostoru :: název funkce) NSFunkce::AllocPole()











Poslední úpravy 2017-10-09