Arvutiteaduse instituut
  1. Kursused
  2. 2019/20 kevad
  3. Programmeerimine keeles C++ (MTAT.03.158)
EN
Logi sisse

Programmeerimine keeles C++ 2019/20 kevad

  • Pealeht
  • Praktikumid
    • Lahenduste esitamine
    • Tulemused
  • Eksamiajad
  • Juhendid
  • Viited

Programmeerimine keeles C++

Praktikum 3: mallid, C++ standardteegi konteinerid, iteraatorid

Ülesanded

Üldised tingimused

Tähtis! Loe läbi ülesannete vormistamise tingimused aine veebilehelt! Ülesandeid esitatakse läbi aine veebilehel asuva vormi. E-posti teel lahendusi vastu ei võeta. Küsimustega pöörduda aine listi või praktikumijuhendaja poole.

Lahendamiseks on aega 14 päeva.

Tähtaeg: 05.04.2020 23:59:59

Ülesanne 1 – Geomeetria suvalise mõõtmete arvuga ruumis

Selles praktikumis kirjutame seni kõige täiuslikumad punkti, sirglõigu ja kera klassid. Nimelt kasutame klassimalle, et luua geomeetrilisi objekte suvalise mõõtmega ruumis (märkus: ma palun, et teie kood annaks triviaalseid vastuseid ka siis, kui parameetritega määratakse 0-mõõtmeline ruum). Järgmiste klasside realiseerimiseks kasutage malle.

Kui teil ei teki cpp-faile, siis ärge tehke ka geometry-teegile .a faili. Esimeses ülesandes võib nii juhtuda kergesti.

1.1. Universaalne punkt (point.h) (3 punkti)

Looge klass Point, millele saab ette anda koordinaatide arvu (template <unsigned short n>). Etteantav mittenegatiivne täisarv n määrab, mitu murdarvulist mõõdet vektoril on. Punkti koordinaate salvestage STL konteinerklassi std::list abil klassi muutujas nimega coords.

Mõned näited:

Point<2> kahem66tmelinePunkt; // punkt tasandil
Point<10> kymnem66tmelinePunkt; // punkt kümnemõõtmelises ruumis

Lisage klassile meetodid:

MeetodEesmärk
Point<n> ()algväärtustab koordinaadid nullidega
Point<n> (list<float> crds)väärtustab vektori koordinaadid etteantud väärtustega
float distanceFrom (Point<n> v)tagastab kauguse teisest sama mõõtmehulgaga punktist
string toString ()tagastab vektori esituse sõnena (x1, x2, ..., xn)
operator <<väljastab vektori andmed (kasuta ära toString meetodit)

Väljundvoogu nihutamise operaatori ülelaadimisel on abiks friend võtmesõna.

NB! Võtmesõna friend kasutamine mallide sees võib põhjustada veidraid vigu või hoiatusi kompileerimisel. Vaata lisaks https://isocpp.org/wiki/faq/templates#template-friends

NB! Operaatori ülelaadimist on lihtsam realiseerida, kui parameetriks antud Point objekt pole konstant. Ilusama lahenduse kirjutamiseks vaata vihjeid viimasel leheküljel.

Juhul, kui tekivad veaolukorrad, näiteks kui malliga määratud koordinaatide arv n erineb etteantud koordinaatide vektori suurusest, visake string-tüüpi erind (vt materjali). Erindi teksti kirjutage inimkeelne selgitus selle kohta, mis toimus. Arvestage, et 0-koordinaadiga vektor on põhimõtteliselt täiesti lubatud ning seda veajuhuks lugema ei peaks.

1.2. Universaalne sirglõik (line.h) (1 punkt)

Looge klassimall Line, mille parameetriks on punkti klass T (template <class T>). Klass esindab sirglõike üle suvalise mõõtme punktide. Klassil on kaks muutujat – p1 ja p2, mõlemad on tüüpi T – need esindavad sirglõigu tippe. Tulemusena peab saama teha kahe tipuga sirglõike nii:

Line< Point<2> > kahem66tmelineSirgl6ik;
Line< Point<7> > seitsmem66tmelineSirgl6ik;

Lisage klassile meetodid:

MeetodEesmärk
Line<T> ()vaikekonstruktor – loob tipud (T vaikekonstruktoriga)
Line<T> (T np1, T np2)parameetritega konstruktor – väärtustab klassi elemendid
float length ()tagastab sirglõigu pikkuse kasutades klassi T meetodit distanceFrom
string toString ()tagastab lõigu esituse sõnena ((tipp1)-(tipp2))
operator <<väljastab lõigu andmed (kasuta ära toString meetodit)

1.3. Universaalne kera (sphere.h) (3 punkti)

Looge klassimall Sphere, mille parameetriks on punkti klass T (template <class T>). Klass esindab kerasid (ja kahemõõtmelisel erijuhul ringe). Klassil olgu T tüüpi muutuja o, mis esitab keskpunkti ja float-tüüpi murdarv r, mis esitab raadiust. Raadius ei tohiks olla kunagi negatiivne.

Tulemusena peab saama teha ringe ja kerasid nii:

Sphere< Point<2> > ring;
Sphere< Point<3> > kera;
MeetodEesmärk
Sphere<T> ()vaikekonstruktor – loob T tüüpi tipu ja paneb raadiuseks nulli
Sphere<T> (T no, float nr)parameetritega konstruktor – kasutab antud tippu ja raadiust
bool contains (T v)tagastab true, kui tipp on kera pinnal või sees, muidu false
bool contains (Line<T> l)tagastab true, kui antud lõik on kera sees, muidu false
void scale (float factor)korrutab kera raadiuse antud väärtusega
string toString ()tagastab kera esituse sõnena ((tipp), raadius)
operator <<väljastab kera andmed (kasuta ära toString meetodit)

See ei ole ülesande osa, aga jätke meelde, et keeles on olemas ka võimalus konkreetsete parameetritega implementatsioonide kirjutamiseks. Näiteks võite realiseerida erijuhtudena kahemõõtmelise kera (ringi) jaoks ümbermõõdu ja pindala ning kolmemõõtmelise kera jaoks ruumala arvutamise. Vastav märksõna, mida uurida, on template specialization.

NB! Ärge muutke soovitatud muutujanimesid ning hoidke muutujad avalikena. Nii on testimine lihtsam. Samuti tehke päisefail geometry.h, mille lisamisel lisatakse nii tipu, sirglõigu kui kera klasside päised. Meenutan, et dokumenteerimine on endiselt kohustuslik!

Ülesanne 2 – universaalse hulknurga klass (3 punkti)

Tulemusena on vaja luua klassimall Polygon, mille parameetriteks on punkti klass T ja täisarv n (template <class T, unsigned short n>). Klass esindab n-tipulisi hulknurki üle etteantud punktide. Lisage klassimallile meetodid:

MeetodEesmärk
Polygon<T, n> ()algväärtustab tipud nullidega
Polygon<T, n> (vector<T> pts)väärtustab vektori koordinaadid etteantud väärtustega
float perimeter ()annab hulknurga perimeetri (külgede pikkuste summa)
string toString ()tagastab hulknurka esitava sõne ((tipp1),...,(tipp2))
operator <<väljastab hulknurga andmed (kasuta toString meetodit)

Vihjeid

Abiks väljundvoogu nihutamise operaatori ülelaadimisel (vaata esmalt teise praktikumi materjalist „Lisalugemist väljundvoogu suunamise operaatori ülelaadimise kohta“).

Kui funktsiooni parameeter on konstant, siis andes selle parameetri edasi mõnele teisele funktsioonile peab ta jääma konstantseks. Näiteks, kui klass on kirjeldatud järgmiselt

class Vector2 {
  ...
  string toString();
  friend ostream& operator<<(ostream& out, const Vector2& vec);
}

Siis ei saa operaatori ülelaadimist realiseerida nii

ostream& operator<<(ostream& out, const Vector2& vec) {
  out << vec.toString();                      // veateade
  return out;
}

Probleem seisneb selles, et kompilaator ei tea, mis toString meetodis tehakse ja kas see meetod muudab Vector2 klassi objekti. Lahenduseks tuleks toString meetodi lõppu kirjutada const (string toString() const;), mis tagab, et objekti seal meetodis ei muudeta ning võimaldab toStringile teha väljakutseid konstantsete muutujate pealt.

Lisaülesanne 3 – funktsiooniobjektid (1 lisapunkt)

Üldised nõuded

Selle ülesande lahendamise käigus saate harjutada algoritmide ja funktsiooniobjektidega töötamist. Tulemusena tekkiv kood peaks sisalduma teegifailis nimega libmyfunctors.a ja vastav päis olgu myfunctors.h. Lahenduse testimiseks kirjutan ma programmi, kus rakendan teie kirjutatud koodi ning kontrollin tulemuste vastavust ülesande nõuetele. Soovitan teil teha testprogramm, kus oma lahendust ise järele proovite. Testprogrammi ei hinnata.

Lahendus paigutage samasse kataloogipuusse esimese ülesande geomeetriakoodiga. Makefile peab vaikimisi ehitama valmis teegi.

Osa 3.1 – ühe parameetriga ja olekuta funktsiooniobjekt täisruutude äratundmiseks

Kirjutada ühe unsigned long tüüpi parameetriga predikaatfunktor IsSquare, mis tagastab tõese väärtuse, kui etteantud täisarv on mingi täisarvu ruut (näited sobivatest arvudest on 0, 1, 4, 9, 16,...). Funktor peab sobima kasutamiseks algoritmides find_if, count_if, replace_if, remove_if, remove_copy_if. Funktsiooniobjekti võiks realiseerida CPP-failis.

Osa 3.2 –

Ühe parameetriga olekuga funktsiooniobjekt konteineri elementide summeerimiseks

Kiire sissejuhatus olekuga funktorite teemasse. Funktorid võivad olla defineeritud ka enne nende rakendamist. Sellega kaasneb meeldiv lisavõimalus kasutada neid näiteks väärtuste kogumisel. Funktor luuakse enne algoritmi käivitamist ning pärast töö lõppu loetakse objekti seest tulemus. Selle toetamiseks peavad funktori klassis olema lisaks tehtele () defineeritud veel vajalikud muutujad ning meetodid. Teie ülesandeks on kirjutada klassiparameetriga T klassimall SumElements<T>, mida saaks kasutada T tüüpi elemente sisaldavate konteinerite sisu summeerimiseks. Eeldame, et tüübil T on defineeritud tehe + (sobivad näiteks int, float, string). Kui koodis proovitakse objekti luua mõne tüübiga, millel tehet pole, tekib viga.

Funktsiooniobjekti võiks realiseerida päises. Näide sellest, kuidas objekti peaks saama kasutada.

vector<unsigned long> values;            // vektor täisarvudest
SumElements<unsigned long> addThisValue; // sama tüüpi funktor
addThisValue = for_each(values.begin(), values.end(), addThisValue); // summeeri
unsigned long sum = addThisValue.result ();   // loeme kogunenud summa

Lahendus peab töötama nii arvuliste tüüpide kui ka sõnede korral. Vihje: Loogeliste sulgude kasutamine objekti loomisel algväärtustab arvulised tüübid nulliks ja sõned tühisõnedeks. Näiteks

int x;   // x'i väärtuseks võib olla ükskõik mis
int x{}; // x algväärtustatakse nulliks
int x(); // Kompilaator arvab, et tegemist on funktsiooni deklaratsiooniga

Lisainfo:

http://en.cppreference.com/w/cpp/language/value_initialization

http://en.cppreference.com/w/cpp/language/default_initialization

Osa 3.3 – näiliselt juhuslikud reaalarvud

Kirjutada funktsiooniobjekt PseudoRandomGenerator<seed>, mis tagastab juhuslikult genereeritud float tüüpi arvu. Funktsiooniobjekt peab sobima kasutamiseks algoritmide generate ja generate_n abil juhuslikke reaalarve sisaldavate konteinerite (näiteks vektorite) loomiseks. Oluline on, et sama seed väärtuse korral tekkivad erinevate juhuarvude jadad oleksid võrdsed. Erineva seed väärtuse korral tekkivad jadad peavad olema erinevad. Vaata lisaks geometrytest.cpp faili. Juhuslike arvude loomiseks võid kasutada teeki <random> (C++11).

Vaata: http://en.cppreference.com/w/cpp/numeric/random

  • Arvutiteaduse instituut
  • Loodus- ja täppisteaduste valdkond
  • Tartu Ülikool
Tehniliste probleemide või küsimuste korral kirjuta:

Kursuse sisu ja korralduslike küsimustega pöörduge kursuse korraldajate poole.
Õppematerjalide varalised autoriõigused kuuluvad Tartu Ülikoolile. Õppematerjalide kasutamine on lubatud autoriõiguse seaduses ettenähtud teose vaba kasutamise eesmärkidel ja tingimustel. Õppematerjalide kasutamisel on kasutaja kohustatud viitama õppematerjalide autorile.
Õppematerjalide kasutamine muudel eesmärkidel on lubatud ainult Tartu Ülikooli eelneval kirjalikul nõusolekul.
Courses’i keskkonna kasutustingimused