Tentamen i 2D1387 Programsystemkonstruktion med C++
Datum: Måndag 29 augusti, 8-13
Hjälpmedel: En eller två valfria läroböcker om C++
Tid: 5 timmar
Skriv tydligt och ge motiveringar till dina svar. För godkänt krävs 25 poäng.
Maximal poäng är 45.
1. (a) Vad skriver följande kod ut? 5p
(b) Vad skulle skrivas ut om alla virtual togs bort? 5p Inga motiveringar behövs.
using namespace std;
struct A {
A(string s) : name(s) {};
string name;
virtual void print() { cout << "my name is " << name << endl; };
};
struct B : A {
B(string s) : A("made by B"), name(s) {};
string name;
virtual void print() { cout << "my name is " << name << endl; };
};
struct C : B {
C(string s) : B("made by C"), name(s) {};
string name;
virtual void print() { cout << "my name is " << name << endl; };
};
void f1(A p) { p.print();
};
void f2(A & p) { p.print();
};
int main() { B b("Bertil");
C c("Caesar");
A & a(b);
a.print(); // OBS, omkastad ordning b.print();
c.print();
f1(c);
f2(c);
}
1
2. Quicksort består i huvudsak av två funktioner. Dels en rekursiv funktion som delar upp vektorn i mindre delar och dels en partitioneringsfunktion som delsorterar delarna.
(a) Skriv en typparametriserad partitioneringsfunktion som givet ett in- tervall och ett pivotelement sorterar alla element så att de som är större än pivotelementet hamnar till höger i intervallet. 7p (b) Skriv om partitioneringsfunktionen som en funktor. Förutom att par- titionera ska den räkna och komma ihåg antal gånger element byter plats. Om du inte kan lösa a-uppgiften så kan du fortfarande få poäng
genom att skriva en korrekt funktor. 2p
(c) Skriv en funktion med några rader kod som anropar funktorn på ett
meningsfullt sätt. 2p
En korrekt löst b-uppgift räcker för full poäng på de första två delfrågorna.
3. (a) Förklara varför destruktorer bör vara virtuella. Vad kan det få för följder om destruktorn inte är virtuell? Visa med kod ett exempel
med sådana följder. 5p
(b) Ett nytt projekt är tvunget att använda olika komponenter kompi- lerade i olika språk. Komponenterna har funktioner som returnerar flera olika sorters strängar som nullterminerade c-strängar, pascal- strängar, stl-strängar m.m.
Föreslå en minnesnål datatyp som kan lagra och hantera denna bland- ning av strängar internt i projektet. Motivera ditt förslag. 3p
4. (a) Följande ofullständiga kod är en delmängd av koden från ett även- tyrsspel. Alla klasser är inte återgivna. Structarna har flera publika medlemsvariabler(attribut) som är bortklippta.
Koden har problem med hanteringen av dynamiskt minne. Beskriv utförligt minneshanteringsproblemen i dessa metoder: 12p
i. killPeasant ii. killSoldier iii. load
(b) Klassen GameFile innehåller kod som kan läsa data från filsystemet, avgöra vad det är för klass/struct och skapa den. Klassen ClassWit- hAllTheCode är en väldigt stor klass med i princip spelets alla övriga metoder. Övriga klasser och structar innehåller ingen kod utan en- bart publika attribut som initieras i konstruktorn.
Givet koden och den begränsade informationen ovan. Uttala dig om vilken betydelse det har att rooms, people och items är deklarerade i ClassWithAllTheCode som privata attribut. 4p
2
#include <vector>
#include <string>
using namespace std;
struct Room;
struct GameObject {
Room * room; // Det rum objektet befinner sig i };
struct Room {
Room(...) {}; // Attribut bortklippta
vector<GameObject *> room_objects;
};
struct Peasant : GameObject { // -"- Peasant(Room * r, ...) {
r->room_objects.push_back(this);};
};
struct Soldier : GameObject { // -"- Soldier(Room * r, ...) {
r->room_objects.push_back(this);};
};
struct Ghost : GameObject { // -"- Ghost(Room * r, ...) {
r->room_objects.push_back(this);};
};
struct Sword : GameObject { // -"- Sword(Room * r, ...) {
r->room_objects.push_back(this);};
};
// fler liknande structar med enbart data struct GameFile {
void open() {};
GameObject * getPeople() {}; // Ladda data från disk, skapa rätt nytt ob- GameObject * getItem() {}; // jekt och returnera pekaren till objektet // ...
};
class ClassWithAllTheCode { vector<Room *> rooms;
vector<GameObject *> people;
vector<GameObject *> items;
public:
ClassWithAllTheCode() {
rooms.push_back(new Room(1, 2, 3)); // initierar alla rumsförbindelser rooms.push_back(new Room(1));
//...
people.push_back(new Peasant(rooms[1])); // sätt ut folk och föremål people.push_back(new Soldier(rooms[3]));
//...
items.push_back(new Sword(rooms[3]));
//...
}
3
void killPeasant(GameObject * g) { // Ta bort bonden från people-vektorn vector<GameObject *>::iterator i;
for (i = people.begin(); i < people.end(); i++) { if (g == *i) {
people.erase(i);
} } }
void killSoldier(GameObject * g) { vector<GameObject *>::iterator j;
// Ta bort soldaten från det rum denne befinner sig i och skapa ett spöke for (j = g->room->room_objects.begin();
j < rooms[i]->room_objects.end(); j++) { if (g == *j) {
delete g;
rooms[i]->room_objects.erase(j);
rooms[i]->room_objects.push_back(new Ghost(rooms[i]));
} }
// Ta bort soldaten från people-vektorn
for (j = people.begin(); j < people.end(); j++) { if (g == *j) {
delete g;
people.erase(j);
} } }
void load(GameFile file) { GameObject * p;
people.clear();
while (p = file.getPeople()) { people.push_back(p);
}
items.clear();
while (p = file.getItem()) { items.push_back(p);
} }
// fler metoder med logik, AI, interagerande med spelaren m.m.
// ...
void run() { /* ... */ };
};
int main() {
ClassWithAllTheCode game;
game.run();
return 1;
};
4