Objektorienterad programmering: Lösningar till tentamen 2007-11-05

Det här är förslag på lösningar. Det kan finnas andra lösningar som också är korrekta, och det kan hända att en del av lösningarna är mer omfattande än vad som krävs för full poäng på uppgiften. En del av lösningarna är kanske inte fullständiga, utan hänvisar bara till var man kan läsa svaret.

Uppgift 1 (3 p)

class Datum {
private:
    int ar;
    int manad;
    int dag;
public:
    Datum(int ar, int manad, int dag);
    void skriv();
    void las();
    bool lika(Datum rhs);
};
Om man vill vara mer avancerad av sig fungerar det här också bra för lika:
    bool lika(const Datum& rhs);

Uppgift 2 (4 p)

Datum::Datum(int ar, int manad, int dag) {
    this->ar = ar;
    this->manad = manad;
    this->dag = dag;
}

void Datum::skriv() {
    cout << ar << "-" << manad << "-" << dag;
}

void Datum::las() {
    char c;
    cin >> ar >> c >> manad >> c >> dag;
}

bool Datum::lika(Datum rhs) {
    return ar == rhs.ar && manad == rhs.manad && dag == rhs.dag;
}
Ett alternativt sätt att skriva konstruktorn:
Datum::Datum(int ar, int manad, int dag)
    : ar(ar), manad(manad), dag(dag) { }

Uppgift 3 (3 p)

int main() {
    Datum d1(1963, 12, 11);
    Datum d2(1963, 12, 11);

    cout << "Skriv två datum:" << endl;
    d1.las();
    d2.las();
    cout << "Datumen: ";
    d1.skriv();
    cout << " ";
    d2.skriv();
    cout << endl;
    if (d1.lika(d2))
        cout << "Lika!" << endl;
    else
        cout << "Olika!" << endl;
    return 0;
}

Uppgift 4 (3 p)

ostream& operator<< (ostream& out, const Datum& datum) {
    out << datum.ar << "-" << datum.manad << "-" << datum.dag;
    return out;
}

istream& operator>> (istream& in, Datum& datum) {
    char c;
    in >> datum.ar >> c >> datum.manad >> c >> datum.dag;
    return in;
}

bool Datum::operator== (Datum& andra_datumet) {
    return ar == andra_datumet.ar && manad == andra_datumet.manad && dag == andra_datumet.dag;    
}

Uppgift 5 (2 p)

int main() {
    Datum d1(1963, 12, 11);
    Datum d2(1963, 12, 11);

    cout << "Skriv två datum:" << endl;
    cin >> d1 >> d2;
    cout << "Datumen: " << d1 << " " << d2 << endl;
    if (d1 == d2)
        cout << "Lika!" << endl;
    else
        cout << "Olika!" << endl;
    return 0;
}

Uppgift 6 (2 p)

int main () {
    Datum* d1p = new Datum(1963, 12, 11);
    Datum* d2p = new Datum(1963, 12, 11);

    cout << "Skriv två datum:" << endl;
    d1p->las();
    d2p->las();
    cout << "Datumen: ";
    d1p->skriv();
    cout << " ";
    d2p->skriv();
    cout << endl;
    if (d1p->lika(*d2p))
        cout << "Lika!" << endl;
    else
        cout << "Olika!" << endl;

    delete d1p;
    delete d2p;

    return 0;
}

En alternativ lösning:

int main () {
    Datum* d1p = new Datum(1963, 12, 11);
    Datum* d2p = new Datum(1963, 12, 11);

    cout << "Skriv två datum:" << endl;
    cin >> *d1p >> *d2p;
    cout << "Datumen: " << *d1p << " " << *d2p << endl;
    if (*d1p == *d2p)
        cout << "Lika!" << endl;
    else
        cout << "Olika!" << endl;

    delete d1p;
    delete d2p;

    return 0;
}

Uppgift 7 (3 p)

Vi skriver på en textfil. Inmatningen avslutas med filslut. Om programmet läser från tangentbordet, skriver man CTRL-D på Linux och CTRL-Z på Windows.
#include <iostream>
#include <fstream>
using namespace std;

#include <Datum.h> // Eller själva koden direkt i filen

int main() {
    Datum d(0, 0, 0);
    ofstream tsut("datum.txt");
    if (!tsut) {
	cerr << "Kunde inte öppna filen 'datum.txt'.\n";
	return 1;
    }
    cout << "Skriv datum och avlsuta med filslut." << endl;
    while (cin >> d)
	tsut << d << endl;
    return 0;
}
En alternativ lösning, där inmatningen avslutas genom att man matar in datumet 0-0-0:
#include <iostream>
#include <fstream>
using namespace std;

#include <Datum.h> // Eller själva koden direkt i filen

int main() {
    Datum d(0, 0, 0);
    Datum slutdatum(0, 0, 0);
    ofstream tsut("datum.txt");
    if (!tsut) {
	cerr << "Kunde inte öppna filen 'datum.txt'.\n";
	return 1;
    }
    cout << "Skriv datum. Avsluta med datumet 0-0-0." << endl;
    cin >> d;
    while (!d.lika(slutdatum)) {
	tsut << d << endl;
	cin >> d;
    }
    return 0;
}

Uppgift 8 (3 p)

#include <iostream>
#include <fstream>
using namespace std;

#include <Datum.h> // Eller själva koden direkt i filen

int main() {
    Datum d1(0, 0, 0);
    cout << "Skriv ett datum: ";
    cin >> d1;
    Datum d(0, 0, 0);
    ifstream tsin("datum.txt");
    if (!tsin) {
	cerr << "Kunde inte öppna filen 'datum.txt'.\n";
	return 1;
    }
    int antal = 0;
    while (tsin >> d)
	if (d == d1)
	    ++antal;
    cout << "Datumet " << d1 << " förekom " << antal << " gånger på filen 'datum.txt'.\n";
    return 0;
}

Uppgift 9 (9 p)

a) (3p)

class Fartyg {
private:
    string namn;
    Datum byggdes;
    static Fartyg* first;
    Fartyg* next;
public:
    Fartyg(string namn, Datum byggdes);
    virtual void skriv();
    virtual int antal_kanoner();
    static Fartyg* get_first();
    Fartyg* get_next();
};

b) (3p)

Fartyg* Fartyg::first = 0;

Fartyg::Fartyg(string namn, Datum byggdes) :
    namn(namn), byggdes(byggdes)
{
    next = first;
    first = this;
}

void Fartyg::skriv() {
    cout << "Fartyget " << namn << " från " << byggdes << endl;
}

int Fartyg::antal_kanoner() {
    return 0;
}

Fartyg* Fartyg::get_first() {
    return first;
}

Fartyg* Fartyg::get_next() {
    return next;
}

c) (1p)

Datum td(1911, 5, 31);
Fartyg t((string)"Titanic", td);
t.skriv();
En alternativ lösning:
Fartyg t("Titanic", Datum(1911, 5, 31));
t.skriv();

d) (2p)

void skriv_alla_fartyg() {
    Fartyg* p = Fartyg::get_first();
    while (p != 0) {
        p->skriv();
        p = p->get_next();
    }
}

Uppgift 10 (8 p)

a) (2p)

class Slagskepp : public Fartyg {
private:
    int kanoner;
public:
    Slagskepp(string namn, Datum byggdes, int kanoner);
    virtual void skriv();
    virtual int antal_kanoner();
};

b) (2p)

Slagskepp::Slagskepp(string namn, Datum byggdes, int kanoner) :
    Fartyg(namn, byggdes), kanoner(kanoner) { }


void Slagskepp::skriv() {
    Fartyg::skriv();
    cout << "Det är ett slagskepp med " << kanoner << " kanoner." << endl;
}

int Slagskepp::antal_kanoner() {
    return kanoner;
}

c) (1p)

Funktionen behöver inte ändras alls. Funktionen skriv är virtuell, och därför anropas rätt version i varje fartygsobjekt, trots att det fartygsobjektet anges med en pekare till basklassen Fartyg. Att man (ibland) inte behöver ändra existerande kod som ska arbeta med nya datatyper, är en av fördelarna med objektorienterade språk.

d) (1p)

bool besegrar(Slagskepp s1, Slagskepp s2) {
    return s1.antal_kanoner() > s2.antal_kanoner();
}

e) (2p)

Datum yd(1940, 8, 8);
Slagskepp y((string)"Yamato", yd, 61);

Datum id(1942, 8, 27);
Slagskepp i((string)"Iowa", id, 158);

if (besegrar(y, i))
    y.skriv();
else if (besegrar(i, y))
    i.skriv();
else
    cout << "Oavgjort!" << endl;


Thomas Padron-McCarthy (Thomas.Padron-McCarthy@tech.oru.se) 15 november 2007