Høgskolen i Gjøvik Avdeling for Teknologi Kontinuasjonseksamen FAGNAVN: FAGNUMMER: Objekt-orientert programmering L 183 A EKSAMENSDATO: 3. januar 2001 KLASSE: 99HINDA / 99HINDB / 99HINEA 99HDMUA / 99HDMUB TID: 09.00-13.00 FAGLÆRER: Frode Haug ANTALL SIDER UTLEVERT: TILLATTE HJELPEMIDLER: 8 (inkludert denne forside) Alle trykte og skrevne. Kontroller at alle oppgavearkene er tilstede. Innføring med penn, evt. trykkblyant som gir gjennomslag. Pass på at du ikke skriver på mer enn ett innføringsark om gangen (da det blir uleselige gjennomslag om flere ark ligger oppå hverandre når du skriver). Ved innlevering skilles hvit og gul besvarelse og legges i hvert sitt omslag. Oppgavetekst, kladd og blå kopi beholder kandidaten. Ikke skriv noe av din besvarelse på oppgavearkene. Husk kandidatnummer på alle ark.
NB: Oppgave 1a, 1b, 1c og 2 er totalt uavhengige og kan derfor løses separat. Oppgave 1 (30%) a) Det nedenfor stående programmet var det ønskelig at gav følgende utskrift: Navn: Astrid Andersen Kjønn: Kvinne Ant.barn: 2 Navn: Brynjulf Berg Kjønn: Mann Har skjegg Navn: Christian Carlsen Kjønn: Mann Har ikke skjegg Navn: Dagrun Dager Kjønn: Kvinne Ant.barn: 0 Navn: Astrid Andersen Kjønn: Kvinne Ant.barn: 4 Men, i koden er det fem feil av typen syntaktiske (som kompilatoren reagerer på) og/eller semantiske (logiske, som gjør at programmet ikke fungerer som ønsket). Hvilke? NB: Tallene helt til venstre på hver linje er ikke en del av koden, men kun ment som linjenummer, slik at du enklere kan henvise til hvor feilene er å finne. 1 #include <iostream> // cout 2a #include <cstring> // strcpy 2b using namespace std; 3 enum kjonn { kvinne, mann ; // Oppramstype for kjønn. 5 class Person { // Baseklasse. 5 protected: 6 char* navn; // Personens navn. 7 kjonn kj; // Personens kjønn. 8 public: // Constructor som initierer variable: 9 Person(char* nvn, kjonn k = kvinne) // Default-kjønn er kvinne. 10 { strcpy(navn, nvn); kj = k; // Kopierer navn og setter kjønn. 11 ~Person() // Destructor. 12 { delete [] navn; // Frigir allokert memory. 13 virtual void display() // Skriver ut objektets data: 14 { cout << "\nnavn: " << navn << "\n\tkjønn: " 15 << (kj == kvinne? "Kvinne" : "Mann"); 16 ; 17 class Kvinne : public Person { // Kvinne-klasse. 18 private: 19 int ant_barn; // Antall barn kvinnen har. 20 public: 21 Kvinne(char* nvn, int ant) : Person(nvn) // Constructor. 22 { ant_barn = ant; // Setter "antall barn" 23 void flere_barn(int n = 1) // Default er et barn til. 24 { ant_barn + n; // Øker med (tillegg på) "n" barn. 25 void display() // Skriver kvinnens data: 26 { Person::display(); cout << "\tant.barn: " << ant_barn; 27 ; 2
28 class Mann : public Person { // Mann-klasse. 29 private: 30 bool har_skjegg; // Har (ikke) skjegg. 31 public: 32 Mann(char* nvn, bool har) : Person(nvn, mann) // Constructor. 33 { har_skjegg = har; // Setter om har (ikke) skjegg. 34 void display() // Skriver mannens data: 35 { Person::display(); 36 cout << "\thar " << ((!har_skjegg? "ikke " : "") << "skjegg"; 37 ; 38a int main() { // Hovedprogram: 38b int i; // Løkkevariabel. 39 Person* personer[4]; // Array av pekere til personer. 40 personer[0] = new Kvinne("Astrid Andersen", 2); // Oppretter nye 41 personer[1] = new Mann("Brynjulf Berg", true); // kvinne - og 42 personer[2] = new Mann("Christian Carlsen", false); // manns-objekter: 43 personer[3] = new Kvinne("Dagrun Dager", 0); 44 for (i = 0; i <= 3; i++) 45 personer[i]->display(); // Skriver objektenes data. 46 personer[0]->flere_barn(2); // Kvinnen har fått to barn til. 47 personer[0]->display(); // Skriver data om henne. 48 for (i = 0; i <= 3; i++) 49 delete personer[i]; // Frigir memory for alle personene. 50 cout << \n ; 51 return 0; 52 b) Hva blir utskriften fra følgende program (litt hjelp: det blir 5 linjer): #include <iostream> #include <cstring> using namespace std; void funk(char txt[], int n = 3, char ch = 'T') { txt[n] = ch; txt[2*n] = ch+2; void funk(char txt[], char ch) { txt[7] = txt[1] = ch; ch = 'K'; void funk(char txt[], char & ch, int n) { ch = txt[n]; strcpy(txt, "STORMBRINGER"); int main() { char tekst[] = "LYKKETREFFET"; char tegn = 'A'; funk(tekst); funk(tekst, tegn); funk(tekst, 5, 'B'); funk(tekst, tegn, 5); funk(tekst, 2, tegn); return 0; cout << tekst << '\n'; cout << tekst << " " << tegn << '\n'; cout << tekst << '\n'; cout << tekst << " " << tegn << '\n'; cout << tekst << '\n'; 3
c) Hva blir utskriften fra følgende program (litt hjelp: det blir 4 linjer): #include <iostream> using namespace std; char tekst[][6] = { "ABCDE", "BCDEF", "CDEFG", "DEFGH", "EFGHI" ; int main() { char* p; int i; cout << tekst[3] << '\n'; for (i = 0, p = tekst[0]; i < 7; i++, p += 4) cout << *p << " "; cout << '\n'; tekst[1][1] = tekst[1][2] = tekst[1][3] = 'T'; cout << tekst[1] << '\n'; for (i = 0, p = &tekst[0][1]; i <=3; p = &tekst[++i][i+1]) cout << *p << " "; cout << '\n'; return 0; Oppgave 2 (70%) NB: Les hele teksten for denne oppgaven nøye, før du begynner å besvare noe som helst. Studer spesielt vedlegget (const er, global variable (to steder), klasser (to stk.) og hovedprogram), slik at du får klarhet i hvordan programmet skal fungere. Oppgaven i korthet Du skal i denne eksamensoppgaven lage et enklet program for å administrere frukt- og bærplukkere på en gård. Det som kan plukkes er: epler ( E ), moreller ( M ), solbær ( S ) og jordbær ( J ). Hver plukker har hvert sitt unike nummer/id. Plukkerne ligger lagret i en egen liste, sortert på dette nummeret/id en. En person kan: ankomme gården, og bli lagt inn som ny plukker (oppgave 2b). avslutte sitt arbeide på gården, og få oppgjør for utført innhøstning (oppgave 2c). levere et visst antall kilo av det vedkommende plukker (oppgave 2d). Data om plukkerne kan leses fra/skrives til fil (oppgave 2e og 2f). Dessuten er det et eget objekt ( pris ) som holder orden på prisen en plukker får for å plukke en kilo av en gitt frukt/bær (oppgave 2a). Datastrukturen Datastrukturen skal altså bestå av: en sortert liste med plukkerne ( plukkere ). en variabel ( nummer ) som fortløpende teller opp plukkernes unike ID. ett objekt ( pris ) av typen Kilopris. 4
Oppgaven a) Skriv innmaten til de to funksjonen inni klassen Kilopris. Lag innmaten til constructoren. Denne skal lese ANT_SLAG flyttall fra filen KILOPRIS.DTA inn i arrayen pris. (Om du bruker >> ved filinnlesningen, så spiller det ingen rolle om tallene ligger på hver sin linje, eller på samme linje med blanke imellom.) Lag innmaten til funksjonen float hent(char slag). Ut fra om inn-parameteren er E, M, S eller J skal funksjonen returnere innholdet i henholdsvis skuff nummer 0, 1, 2 eller 3 i arrayen pris. (Funksjonen hent får du bruk for i oppgave 2c.) b) Skriv innmaten til funksjonen void ny_plukker() Funksjonen leser den nye plukkerens navn og hvilken type frukt/bær vedkommende skal plukke. Denne typen skal være en av typene: E, M, S eller J. Deretter opprettes et plukker-objekt, med disse to verdiene som parametre til constructoren (som også må initiere noen flere verdier). Vedkommendes tildeles automatisk et nummer/id som er en høyere enn siste registrerte plukker. Dette nummeret skrives på skjermen, og plukkerobjektet legges inn i datastrukturen. c) Skriv innmaten til funksjonen void plukker_slutter() Funksjonen ber først om plukkerens nummer/id. Om dette nummeret ikke finnes, så kommer det en melding om det. I motsatt fall så skrives alle data om plukkeren på skjermen. Deretter beregnes det (og skrives til skjerm) hvor mye vedkommende skal ha utbetalt for det arbeidet/plukkingen som er utført. Utbetalingen beregnes ved å gange antall kilo som vedkommende har plukket med det tallet som pris-objektet returnerer, når man ber om kiloprisen for den typen som vedkommende har plukket. Til slutt slettes plukkerobjektet fra hukommelsen. d) Skriv innmaten til funksjonen void plukket_kilo() Funksjonen ber først om plukkerens nummer/id. Om dette nummeret ikke finnes, så kommer det en melding om det. I motsatt fall så skrives alle data om plukkeren på skjermen. Deretter bes det om et kiloantall som skal ligge mellom 0 og 100. Plukkeren får tillagt dette antall kilo (bruk gjerne overloading av += -operatoren), og dataene om vedkommende skrives igjen på skjermen. e) Skriv innmaten til funksjonen void les_fra_fil() Filen PLUKKERE.DTA har formatet (mellom feltene på hver linje er det to blanke): <Nummer/ID> <Plukkers navn> <Antall kilo> <Frukt-/bærslag: Dvs. bokstaven: E, M, S eller J> Ett eksempel med de to første postene kan være: 1 Arne Amundsen 12 E 2 Birgit Bonde 29 M 5
Funksjonen skal lese inn alle dataene på denne filen, opprette plukker-objekter og legge dem inn i datastrukturen. Etter at et nytt nummer/id er funnet på filen, så la gjerne plukker-objektet selv (vha. en annen constructor ift. den laget i oppgave 2b) lese sine data videre på filen. NB: Husk å oppdatere den globale variabelen nummer. f) Skriv innmaten til funksjonen void skriv_til_fil() Funksjonen skal skrive alle plukker-objektenes data til filen PLUKKERE.DTA, på det samme formatet som beskrevet ovenfor. La objektene selv skrive sine data til fil, etter å ha fått adressen til fil-objektet inn som parameter. Husk at objektene skal ikke slettes fra hukommelsen, men tas ut, skrives til fil og legges tilbake i listen igjen. Annet (klargjørende?): Du skal bruke LISTTOOL ved løsning av denne oppgaven. Alle const er, klasser, klasse-medlemmer og globale variable du trenger er allerede ferdig definert. Du trenger altså ikke definere flere slike, men fritt bruke dem når du lager klassenes/ funksjonenes innmat. Men, du må skrive mye mer innmat (constructorer og funksjoner) til klassen Plukker. En plukker vil trofast holde seg til å plukke en type frukt/bær. Dvs. om en person blir registrert til å plukke solbær ( S ) i oppgave 2b, så holder vedkommende seg til å plukke denne bærtypen, og kommer ikke plutselig med 12 kilo epler i oppgave 2d. Det er ikke mulig å påvirke kiloprisene (dataene inne objektet pris ) på annen måte enn ved å editere direkte på filen KILOPRIS.DTA. Dermed blir dette innlest med nye verdier neste gang programmet startes opp igjen. Utbetaling i oppgave 2c foregår etter nåværende/sist innleste kilopris, uansett om den er høyere eller lavere enn når plukkeren startes sitt arbeide på gården. Dvs. om en plukker har arbeidet på gården i flere dager, og kiloprisen har endret seg i løpet av denne tiden, så får vedkommende utbetalt etter dagens kurs. Vi forutsetter at det er plass til hele listen av plukkere i datamaskinens primærhukommelse. Gjør dine egne forutsetninger og presiseringer av oppgaven, dersom du skulle finne dette nødvendig. Gjør i så fall klart rede for disse i starten av din besvarelse av oppgaven. Lykke til og godt plukk av en god karakter! frode@haug.com 6
Vedlegg: Halvferdig programkode #include <iostream> #include <fstream> #include <cctype> #include "listtool.h" // cout, cin // ifstream, ofstream // toupper // Ulike "verktøy" fra "Listtool". using namespace std; // CONST: const int ANT_SLAG = 4; // Antall ulike frukt-/bærslag. const int NVNLEN = 30; // Max.lengde for personnavn. int nummer; // GLOBALE VARIABLE (1): // Holder orden på siste plukkers unike nummer. class Kilopris { private: float pris[ant_slag]; public: Kilopris() { // KLASSER: // Data om de ulike slagenes kilopris. // Oppgave 2a: Skriv innmaten // Array med prisene en plukker får pr.kilo // hun/han plukker av vedkommende frukt/bær. // Constructor som leser kilopriser inn fra fil: ; // Funksjon som returnerer en kilopris, ut fra en gitt bokstav: float hent(char slag) { // Oppgave 2a: Skriv innmaten // En plukker med unik nummer-id: class Plukker : public Num_element { private: // NB: Har også arvet "number"! char navn[nvnlen]; // Navnet. int ant_kilo; char slag; // Plukket antall kilo frukt/bær. // Slag av frukt/bær som vedkommende plukker // (kan kun være 'E', 'M', 'S' eller 'J'). public: // Ut fra oppgavene 2b-2f må det her lages flere funksjoner. ; // GLOBALE VARIABLE (2): List* plukkere; // Listen (sortert på nummer) av plukkere. Kilopris* pris; // ETT objekt med alle kiloprisene. void skriv_meny(); // DEKLARASJON AV FUNKSJONER: char les(); void ny_plukker(); void plukker_slutter(); void plukket_kilo(); void les_fra_fil(); void skriv_til_fil(); 7
int main() { // HOVEDPROGRAMMET: char kommando; pris = new Kilopris; // Oppgave 2a plukkere = new List(Sorted); les_fra_fil(); // Oppgave 2e skriv_meny(); kommando = les(); while (kommando!= 'Q') { switch(kommando) { case 'N': ny_plukker(); break; // Oppgave 2b case 'S': plukker_slutter(); break; // Oppgave 2c case 'P': plukket_kilo(); break; // Oppgave 2d case 'F': skriv_til_fil(); break; // Oppgave 2f case 'D': plukkere->display_list(); break; default: skriv_meny(); break; kommando = les(); return 0; // DEFINISJON AV FUNKSJONER: void skriv_meny() { // Skriver brukerens meny/valg: cout << "\n\nfølgende kommandoer er lovlig:"; cout << "\n\tn - Ny plukker ankommer."; cout << "\n\ts - plukker Slutter."; cout << "\n\tp - Plukket N nye kilo."; cout << "\n\tf - skriv data til Fil."; cout << "\n\td - Display listen av plukkere."; cout << "\n\tq - Quit / avslutt"; char les() { // Leser og returnerer ETT upcaset tegn. Char ch; cout << "\n\nkommando: "; cin >> ch; cin.ignore(); return (toupper(ch)); void ny_plukker() { // Oppgave 2b: Skriv innmaten void plukker_slutter() { // Oppgave 2c: Skriv innmaten void plukket_kilo() { // Oppgave 2d: Skriv innmaten void les_fra_fil() { // Oppgave 2e: Skriv innmaten void skriv_til_fil() { // Oppgave 2f: Skriv innmaten 8