Sid 1 av 8
Datavetenskap
Tentamen för DAV A02 Programutvecklingsmetodik, 5 p
måndag 2006-01-16 kl. 08.15-13.15
Tentamen består av 8 sidor.
Ansvariga lärare:
Kerstin Andersson, Robin Staxhammar
Tillåtna hjälpmedel:
Carrano, F.M., Data Abstraction and Problem Solving with C++
Engelsk-svenskt/svensk-engelskt lexikon
Betygsgränser:
Tentamensgränser
3 = 20-26,5 poäng
4 = 27-33 poäng
5 = 33,5-40 poäng
Kursgränser
3 = 30-39,5 poäng
4 = 40-49,5 poäng
5 = 50-60 poäng
Ange alla antaganden!
Skriv tydligt! (Går inte skriften att läsa är det likställt med ett felaktigt svar.)
Börja varje uppgift på ett NYTT papper!
Skriv alla dina svar på skrivpapper, skriv INTE på tentan!
LYCKA TILL!
1
ADTn List (4 p)
ADTn List finns tillgänglig i två implementerade representationer, som en länkad lista och som
en arraybaserad lista, båda gjorda i C++ med klasser.
a) En klientprogrammerare, Emelie, tänker använda en av de implementerade
representationerna. Vilken ska hon välja? Motivera ditt svar. (2 p)
b)
En annan klientprogrammerare, Tor-Jan, vill använda objekt av båda representationerna.
Men han har bara fått ett gränssnitt till listan och nu är han arg. Han ringer upp dig, du är
ju den ansvarige för båda dessa implementationer. Han ställer nu frågan; "Hur ska jag
kunna veta vilka operationer som gäller för varje specifik lista?".
Din uppgift är nu att ge Tor-Jan ett välmotiverat svar, annars kommer han aldrig mer att
köpa mjukvara av dig. (2 p)
Sid 2 av 8
2
ADTn Bankomat (10 p)
Nedan har delar av ADTn Bankomat, som skall vara en mjukvaruimplementation av en
vanlig bankomat, representerats med en klassdefinition i C++. Bankomaten är en vanlig,
enkel bankomat. Man kan ta ut pengar samt kontrollera sitt saldo
I övrigt kan en användare trycka fel och denne måste då få chansen att rätta till sitt misstag.
Av någon anledning kanske en användare vill avbryta uttaget, det måste också gå såvida
hon/han inte genomfört alla de steg som krävs för att ta ut pengar. Användaren ska kunna
välja om han/hon vill ha ett kontoutdrag eller inte.
Du ska nu färdigställa definitionen av ADTn Bankomat genom att utöka klassdefinitionen
nedan med funktioner. Att färdigställa definitionen innebär att du ska specificera alla
nödvändiga operationer tillsammans med för- och eftervillkor.
Den privata delen av klassdefinitionen är fullständig, där ska inget läggas till. Dessutom är
den privata delen inte nödvändig för specifikationen av ADTn, utan endast för
implementationen, och är endast där för att ge dig lite vägledning i specifikationen av ADTn.
********Du ska EJ implementera bankomaten. ********
OBS!
Observera att detta är en ADT, du ska inte göra någon användarapplikation. Du ska anta att
inga oväntade externa fel uppstår, t ex innebär det att uppkopplingen mot banken inte kan gå
fel. Du ska inte blanda in banken för autentisering och uppdatering av bankkontot o s v.
Tänk heller inte på displayen, den enda operation som behövs för att visa tillståndet på
displayen är den som redan finns nedan. Fokusera på att bara modellera själva bankomatens
funktionalitet.
class Bankomat
{
public:
//Pre: true
//Post: En bankomat är skapad
Bankomat()
//Pre: true
//Post: Bankomaten är destruerad
~Bankomat()
//Pre: true
//Post: Nuvarande tillstånd är utskrivet på displayen
void visaTillstandPaDisplayen();
private:
Display* terminalFonster;
KnappSats* knappar;
UtmatningsEnhet* penningUtmatare;
UtmatningsEnhet* kontoUtdragsUtmatare;
Sid 3 av 8
KortmatningsEnhet* kortInOchUtmatare:
KortLasare* kortLasare;
bool pinOK;
KortNummer* kortNummer;
bool kortOK;
Bankomat(const Bankomat& original);
Bankomat& operator=(const Bankomat& rhs);
};
3
Kontrakt (6 p)
a) I klassen List ingår bl a operationerna isElement och getElement i det publika
gränssnittet. Kontraktet för operationen getElement kan skrivas på två olika sätt, enligt
nedan
//Pre: true
//Post: result = true om det finns ett element på positionen
//"position", false annars.
bool isElement(int position);
Alternativ 1
//Pre: isElement(position)
//Post: Elementet på positionen "position" har returnerats.
int getElement(int position);
Alternativ 2
//Pre: true
//Post: Om positionen "position" är giltig har elementet på
positionen "position" returnerats, annars har -1 returnerats.
int getElement(int position);
Vilket alternativ är bäst? Varför? Motivera ditt svar väl. (3 p)
b) I klassen List finns också operationen isEmpty.
//Pre: true
//Post: result = true om listan är tom, false annars.
bool isEmpty();
Är detta ett svagt kontrakt? Motivera ditt svar. (1 p)
Sid 4 av 8
c) Kön nedan använder en lista i sin implementation.
template <typename T>
class Queue
{
public:
//Pre: ???
//Post: The first element in the queue has been removed
void dequeue();
//…
private:
List<T> queueList;
};
Operationen dequeue ovan använder operationen remove i klassen List i sin
implementation.
template <typename T>
void Queue::dequeue()
{
queueList.remove(1);
}
Listans operation remove har ett gränssnitt enligt nedan.
//Pre: 1 <= position <= size()
//Post: The element at the position "position" has been removed.
void remove(int position)
Hur måste förvillkoret för dequeue ovan se ut? Varför, samt vilka antaganden har gjorts?
Motivera dina svar. (2 p)
Sid 5 av 8
4
Cirkulär kö (5 p)
Om man använder en array för att lagra en kö uppstår snart ett problem, nämligen att arrayen tar
slut. Ett sätt att lösa problemet är att göra arrayen cirkulär, vilket innebär att man efter sista
elementet (maximalt index) i arrayen går till element med index 0.
Din uppgift är att skapa en klass som heter Circ_Ko utgående från nedanstående kod. Klassen
skall ha normala köegenskaper vad gäller insättning och borttagande. Som du ser saknas
returvärden, parametrar, datamedlemmar och implementation för funktionerna i klassen. Skriv
allt detta och skriv också för- och eftervillkor. Du ska inte skriva några drivrutiner.
Ledning: Som datamedlemmar är det lämpligt att ha en array där elementen i kön lagras och
variabler som håller koll på köns storlek och köns början och slut.
class Circ_Ko
{
public:
typedef int datatyp;
Beskrivning: En tom kö skapas.
Pre: true
Post: en tom kö har skapats
Circ_Ko();
Beskrivning: En kö tas bort.
Pre: true
Post: kön har tagits bort
~Circ_Ko();
Beskrivning: Lägger till ett element sist i kön.
Pre: ?
Post: ?
? KoAdd(?);
Beskrivning: Tar bort ett element först i kön.
Pre: ?
Post: ?
? KoRemove(?);
Beskrivning: Kontrollerar om kön är tom.
Pre: ?
Post: ?
? KoIsEmpty(?);
Beskrivning: Kontrollerar om kön är full.
Pre: ?
Post: ?
? KoIsFull(?);
Sid 6 av 8
Beskrivning: Returnerar första elementet i kön.
Pre: ?
Post: ?
? KoGetFront(?);
private:
enum {ANT_I_ARRAY = 100};
// plats för datamedlemmar
};
5
Minneshantering (5 p)
a) Vad är copy-konstruktorns uppgift? Vad kan hända om vi inte har definierat
en copy-konstruktor och klassen handhar dynamisk minnesallokering? Exemplifiera. (3 p)
b) Förutom copy-konstruktorn har varje klass tre andra speciella medlemsoperationer.
Namnge dessa och förklara deras respektive uppgift. (2 p)
6
Arv och polymorfism (5 p)
a) Ange tre skäl till varför arv bör användas. (2 p)
b) Visa hur man på bästa sätt använder en array för att lagra objekt av klasserna Dog och
Bird nedan. Visa hur man sätter in några objekt i arrayen. Visa också hur man kan hämta
objekten och anropa operationerna på dem. (3 p)
#ifndef PET_H
#define PET_H
class Pet
{
public:
virtual void speak() = 0;
virtual void eat() = 0;
};
#endif
//*************Dog.h***********//
#include "Pet.h"
class Dog : public Pet
{
public:
virtual void speak();
virtual void eat();
};
//*************Bird.h***********//
Sid 7 av 8
#include "Pet.h"
class Bird : public Pet
{
public:
virtual void speak();
virtual void eat();
};
//********************Dog.cpp**************//
#include "Dog.h"
#include <iostream>
void Dog::speak()
{
std::cout << "Dog::speak()" << std::endl;
}
void Dog::eat()
{
std::cout << "Dog::eat()" << std::endl;
}
//*****************Bird.cpp*****************//
#include "Bird.h"
#include <iostream>
void Bird::speak()
{
std::cout << "Bird::speak()" << std::endl;
}
void Bird::eat()
{
std::cout << "Bird::eat()" << std::endl;
}
7
Binära träd och rekursion (5 p)
a) Ett binärt träd skrivs ut i inorder och preorder med följande resultat:
Inorder: 3, 8, 11, 7, 5, 12, 1, 6, 9, 2, 10, 4
Preorder: 6, 7, 8, 3, 11, 1, 5, 12, 2, 9, 4, 10
Rita upp hur trädet ser ut. (2 p)
Sid 8 av 8
b) Skriv en rekursiv medlemsfunktion, sameTree(BST & aTree), i klassen BST (Binary
Search Tree), som bestämmer om det binära sökträdet är lika med ett annat givet binärt
sökträd. Med lika menas att träden ska ha lika struktur, samt att de har lika element på
respektive plats.
Det binära sökträdet är ett objekt av klassen BST och består av nod-objekt, som tillhör
klassen TreeNode. Eftersom rotpekaren inte får vara synlig/åtkomlig via ett objekt av det
binära trädet måste du skapa två funktioner, en publik (public) gränssnittsfunktion, som i
sin tur anropar en rekursiv privat (private) funktion. (3 p)
Nedan finns några kodfragment från de två klasserna, som du kan ha nytta av:
class TreeNode
{
friend class BST;
private:
int data;
TreeNode* left;
TreeNode* right;
};
class BST
{
public:
//...
bool sameTree(BST &aTree); // Implementera denna !
private:
TreeNode* root;
//...
? sameTree(?); //Implementera denna!
};