Útmutató a 8. laborhoz

Felkészülés a laborra

  1. Ismételje át a sablonokról és az iterátorokról tanultakat (7. és a 8. előadás anyaga)!
  2. Tanulmányozza az előadásokon bemutatott példákat! Töltse le és próbálja ki azokat!

A laborfoglalkozás végén a myset.hpp fájlt kell feltöltenie a Jporta rendszerbe (8. önellenőrző feladat), hogy megkapja a labor elvégzéséért járó pontot! Legalább az első két tesztesetet (ELEKESZULT >= 2) hibátlanul meg kell oldania! A feladatok feltöltésére a laborgyakorlatot követő szombat 06:00-ig van lehetősége.

1. feladatcsoport (~25') megoldásokkal

  1. Töltse le az előkészített laboranyagot a tárolóból https://git.ik.bme.hu/Prog2/labor_peldak/lab_08, majd nyissa meg a generikus1 alkatalógusban található projektet!
  2. Röviden elemezze a tesztprogramot (generikus1_teszt.cpp)! Vegye észre:
    • A ELKESZULT makró értékétől függően egyre több teszteset hajtódik végre.
    • Az egyes tesztesetek (ELKESZULT) új blokkot (szkópot) nyitnak, így elkerülhetőek a névütközések.
    • A tesztprogram használja a korábban már alkalmazott _(...) makrót. A makrónak átadott paraméterek (utasítások, deklarációk) a végrehajtásuk előtt kiíródnak a képernyőre. Így a program végrehajtása soronként követhető.
    • Tudjuk, hogy a C++ alaptípusai nem objektumok. Néha azonban jó lenne, ha egy adott alaptípus objektumként viselkedne, mert szeretnénk a viselkedését valamivel bővíteni. Pl. szeretnénk egy olyan Integer osztályt, ami pont úgy használható, mint az int típus, de a példányai garantáltan 0 kezdőértékkel jönnek létre. Elsőre azt gondolnánk, hogy létre kell hozni egy Integer osztályt, amiben meg kell valósítani az int típus összes műveletét. Helyette azonban elegendő egy olyan osztályt létrehozni, ami képes int adatot tárolni, és implicit módon konvertálható mindkét irányban (Integer <--> int). Így elegendő a konverziós operátorokat megvalósítani, mert a többit már az int típus "tudja".

      Elemezze az Integer osztályt az integer.h fájlban, ami a fent vázolt módon egy olyan egész típust valósít meg, ami alapesetben 0 kezdőértékkel jön létre, és pontosan úgy viselkedik, mint az int típus! Értse meg, hogy miért használható bárhol, ahol az int! Mi biztosítja a konverziót? Állítsa be a ELKESZULT makró értékét 0-ra és futtassa a programot!

    • Adjon a projekthez egy alaptipus.hpp állományt és ebben valósítson meg az Integer osztály mintájára egy Alaptipus sablont, amivel osztályként kezelhető minden alaptípus! Azaz előállítható minden alaptípushoz egy olyan osztály, ami az adott alaptípus helyett használható, és példányai garantáltan 0 kezdőértékkel jönnek létre. Az Alaptipus<double> például double-ként viselkedő osztályt hoz létre.
      Emlékezzen rá, hogy a sablonok fordítási időben példányosodnak. Ezért minden alkatrészüknek az adott fordítási egységben elérhetőnek kell lenni. Így a sablonhoz — legyen az osztálysablon vagy függvénysablon — tartozó kódot fejléc állományba kell írni. Az ilyen header állományokat nevükben is illik megkülönböztetni. Ezért általában .hpp-nek nevezzük a sablon-t tartalmazó fájlokat. Ezek a fájlok azonban nem önálló fordítási egységek, így a többszörös feldolgozásuk ellen ugyanúgy kell védekezni, ahogyan a .h fájlokban szokás.

      Az osztály használatára a ELKESZULT >= 1 esetén lát példát a tesztprogramban. Állítsa be a ELKESZULT makró értékét 1-re és futtassa a programot!

    • Állítsa be a ELKESZULT makró értékét 2-re és fordítsa le a programot!
      A program nem fordul le, mert a kiír függvény második hívásakor a formális és aktuális paraméterek típusa nem egyezik (int* vs double*). Mi a megoldás? Vegye észre, hogy a kiir függvény egy tömbrészlet elemeit írja ki a paraméterként kapott jobbról nyílt intervallumban [first,last)! Azaz, ez a függvény paraméterként két iterátort kap, melyek egy sorozattároló (esetünkben egy mezei tömb) elemeit jelölik ki.
      Alakítsa át a függvényt függvénysablonná! Ehhez nem kell mást tennie, mint a formális paraméterként kapott first és last típusát sablonparaméterként átvenni. Mivel azonos típusúak elegendő egy sablonparaméter! Ne használja ki, hogy ez most pointer, tekintsen ezekre a sablonparaméterekre mint iterátorokra!

      Futtassa a programot az átalakított kiíró függvénnyel!
    • Bővítse és próbálja ki a tesztprogramot más típusokkal is! Lelkesedésétől függően használjon másik alalptípust, vagy tervezzen meg egy nagyon egyszerű osztályt, és valósítsa meg azt egy külön fájlban (pl. komplex.h)! Az egyszerűség kedvéért minden tagfüggvény inline függvény legyen! Készítsen az osztályhoz insertert is! Hozzon létre ebből egy tömböt és alkalmazza rá a kiir sablont! Vegye észre, hogy a kiir sablont már nem kell változtatnia!

    2. feladatcsoport (~60') megoldásokkal

    A laborfoglalkozás végén önellenőrzésként töltse fel az elkészített myset.hpp állományt Jporta rendszerbe úgy, hogy feltöltés előtt ebbe emelje át az ELKESZULT makrót a feladat készültségi fokának megfelelő értékkel! (8. labor, önellenőrzés (myset))!

    1. Navigáljon a letöltött laboranyag (https://git.ik.bme.hu/Prog2/labor_peldak/lab_08) halmaz alkatalógusába és nyissa meg az ott található halmaz projektet!
    2. Röviden elemezze a tesztprogramot (halmaz_teszt.cpp), ami az előző feladatcsoport tesztprogramjához hasonlóan a ELKESZULT makró értékétől függően egyre több kódrészletet futtat:
      • ELKESZULT == 0 estén az Ön által készített Set sablon létezését teszteli.
      • ELKESZULT == 1 esetén a Set működését teszteli néhány alaptípussal.
      • ELKESZULT >= 2 esetén a Set sablont a Point osztállyal teszteli.
      • ELKESZULT >= 3 esetén az Ön által készített equal sablont teszteli.
      • ELKESZULT == 4 esetén az Ön által készített equal sablon specializációját teszteli (Point Y koordinátája nem vesz részt a hasonlításban).
      • ELKESZULT == 5 esetén a szorgalmi feladatnak megfellelően módosított Set osztályt teszteli.
    3. Ötlet: Tárolja el az elemeket és a darabszámot. A fix méretű tömbben egyszerű keresni. Értékadással sincs baj.
    4. Tervezzen egy generikus halmaz osztályt (Set)! Az egyszerűség kedvéért az osztály az előadáson látott fix méretű generikus tömb (Array) osztályhoz hasonlóan egy sablonparaméterként átvett méretű tömbben tároljon! A méret alapértelmezett értéke legyen 10! A létrehozáson, megszüntetésen kívül csak az alábbi három művelettel kell, hogy rendelkezzen az osztály:
      • size - a halmazban levő elemek számát adja (size_t)
      • isElement - megvizsgálja, hogy a paraméterként kapott elem benne van-e a halmazban (bool)
      • insert - paraméterként kapja a halmazba beteendő elemet, ha nincs már hely a tárolóban, dobjon const char* kivételt

      A halmaz használatára az alábbi kódrészlet mutat példát:

         Set<int, 20> max_husz_elemu_int_halmaz;
         max_husz_elemu_int_halmaz.insert(300);
         max_husz_elemu_int_halmaz.insert(300);           // már benne van, nem kell ismét beletenni.
         std::cout << max_husz_elemu_int_halmaz.size();   // elemek száma 1
         max_husz_elemu_int_halmaz.insert(2);
         max_husz_elemu_int_halmaz.insert(-3);
         if (max_husz_elemu_int_halmaz.isElement(200)) 
           std::cout << "A 200 benne van a halmazban" << std::endl;
         else 
           std::cout <<" 200 nincs benne a halmazban" << std::endl;
      
    5. Adjon a projekthez egy új állományt myset.hpp néven, majd valósítsa meg a halmazt ebben az állományban! Mivel az osztálysablon kívül definiált tagfüggvényének definicíója formálisan kicsit bonyolultabb (függvénysablont kell írni), most azt javasoljuk, hogy ne legyen az osztálynak kívül definiált tagfüggvénye.
    6. Tesztelje az elkészített osztályt több lépésben:
      • A tesztprogramban (halmaz_teszt.cpp) állítsa a ELKESZULT makró értékét 0-ra (ez az alapeset), majd fordítsa, futtassa a programot! Ekkor csak néhány elemi teszt fut le: int és char típusra példányosítjuk a sablont és megnézzük, hogy keletkezett-e insert és isElement tagfüggvénye. Lényegében csak azt vizsgáljuk, hogy lefordul-e a kód.
      • Amennyiben nincs szintaktikai hiba, állítsa a ELKESZULT értékét 1-re. Ekkor a tesztprogram a már ismert gtest_lite tesztekkel végrehajt néhány funkcionális tezstet. A megjegyzések segítenek megérteni, hogy mit vizsgálnak a tesztesetek.
      • Tipp:A Point osztályban megvan minden operátor amit a sablon használ?
      • Amennyiben a tesztek jól futnak, állítsa a ELKESZULT értékét 2-re. A program nem fog lefordulni. Miért?
      • Milyen megoldásokat javasol a probléma elhárítására? Alaposan gondolja át, és csak ezután nézze meg a mi javaslatainkat!
    7. A fenti lehetőségek közül a b) esetnek megfelelően készítsen a Point osztályhoz globális összehasonlító operátort (az osztály módosítása nélkül)! Ezt is a myset.hpp fájlban valósítsa meg, bár nem oda való, azonban a Jporta a feltöltés miatt most így egszerűbb! Fordítson, futtasson!
    8. Tegyük fel, hogy most szeretnénk egy másik halmazban is pontokat (Point) tárolni, de ebben a halmazban csak az X koordináta alapján akarjuk a pontokat megkülönbözteti. A példa kapcsán látható, hogy a halmazban történő tároláshoz több fajta összehasonlítás is elképzelhető még ugyanarra az adatra is. Az, hogy milyen hasonlítást alkalmazunk, nem az adat jellemzője, hanem a tárolás jellemzője. Ebből két dolog következik:
      • A halmazban, mint tárolóban meg kell oldani, hogy az összehasonlítás könnyen lecserélhető legyen, pl. paraméterrel.
      • A legtöbb esetben azonban jó az operator==, így jó lenne azt alapértelmezettnek hagyni.

      Készítsen egy bool equal(const T&, const T&); sablont, ami a paraméterként kapott generikus adatokat összehasonlítja a szokásos operator== művelettel!
      Az 5. feladatban számba vett lehetőségek közül a d) estenek megfelelően módosítsa a Set sablont úgy, hogy az equal sablont használja az elemek összehasonlítására. Állítsa ELKESZULT makró értékét 3-ra és fordítson, futtasson!

    9. Specializálja az equal sablont úgy, hogy a Point osztályból származó objektumok összehasonlításakor csak az X koordinátát vegye figyelembe! Állítsa ELKESZULT makró értékét 4-re és fordítson, futtasson!
    10. Szorgalmi feladat: Az 5. feladatban számba vett lehetőségek közül az e) estenek megfelelően alakítsa át az elkészített sablont úgy, hogy az összehasonlító függvényt az osztály sablonparaméterként vegye át, melynek alapértelmezése a korábban elkészített bool equal(const T&, const T&) függvénysablon legyen!
      Készítsen egy bool Xequal(const Pont&, const Pot&); függvényt is, ami csak az x koordinátak alapján hasonlít össze! Ezt is a myset.hpp fájlba tegye, bár nem oda való! (Laborvezetőjével beszélje meg, hogy az Xequal helye hol lenne!)
      Állítsa ELKESZULT makró értékét 5-re és fordítson, futtasson! Ne felejtse el kitörölni, az equal sablon Point osztályra történt specializációját! Az már nem kell, van helyette Xequal.
    11. Töltse fel az elkészített myset.hpp állományt Jporta rendszerbe! Ne felejtse el átemelni a halmaz_tesz.cpp fáljból a myset.ccp-be az ELKESZULT makrót a feladat készültségi fokának megfelelő értékkel! Ha elfelejti, a Jporta, ELKESZULT==2 értéket tételez fel.(8. labor, önellenőrzés (myset)).

    Jó munkát!

    Szeberényi Imre

    Utolsó frissítés: 2021-04-12 17.40