PROG 23 – Objekt-Orientert Programmering i C++
Løsningsforslag til obligatorisk oppgave 1
Vårsemesteret 1999
 


Problemstilling

Du skal lage et program som skal holde orden på en del konti. Programmet skal ha følgende funksjoner:

  • Opprett ny konto i arkivet.
  • Søk etter konto i arkivet, søk etter kontonummer og returner kontoen.
  • Slett konto i arkivet, slett konto med gitt kontonummer.
  • Endre saldo på konto i arkivet.
  • Sjekk om saldo på konto med oppgitt kontonummer er overtrukket.
  • Vis alle konti som er lagret i arkivet.
  • Det skal lages et enkelt lite hovedprogram med en meny som gir tilgang til de ønskede funksjoner som programmet skal ha. Bruk en konsoll-applikasjon (DOS).

    Hver konto skal inneholde opplysninger om

  • Kontonummer
  • Saldo

  • Analyse

    Ser at problemstillingen inneholder et arkiv-objekt som igjen inneholder mange konto-objekt. I tillegg til et arkiv med saldo er det også et behov for en meny. Denne skal være tekstbasert og fungere som et mellomledd mellom arkivet og brukeren av programmet. Velger å se bort fra meny-delen i første omgang og ser på de ulike funksjonene til arkivet og kontoene. Menyen skal jo likevel kun videreformidle brukerens ønske.

    Opprett ny konto
    Det lages et konto-objekt, leses inn informasjon til dette og konto-objektet lagres i arkivet.

    C++

    Søk etter konto
    Kontonummer leses, det søkes i arkivet etter konto med dette kontonummeret, kontoen returneres slik at den kan vises.

    C++

    Slett konto
    Kontonummer leses, det søkes i arkivet etter konto med dette kontonummeret og når kontoen finnes, slettes den og fjernes fra arkivet.

    C++

    Endre saldo på gitt konto
    Kontonummer leses, det søkes i arkivet etter konto med dette kontonummeret, kontoen returneres slik at saldoen til kontoen kan endres.

    C++

    Sjekk om saldo er overtrukket
    Kontonummer leses, det søkes i arkivet etter konto med dette kontonummeret, kontoen returneres slik at det kan sjekkes om saldoen til denne kontoen er overtrukket.

    C++

    Vis alle konti
    Arkivet vises. Arkivet må vise hver enkelt konto.

    C++


    Utforming

    Ut fra diagrammene over kan vi nå definere klassene konto og arkiv. Merk at standard konstruktør, kopikonstruktør, destruktør og tilgangsmetoder alltid er med.

    Velger å la arkivet være en tabell med pekere til konti. Tabellen er ikke ordnet og skal være fylt opp fra element nr 0 og til antall lagrede element – 1.

    Konto
    Datamedlemmer (variabler)

    Metoder Arkiv

    Datamedlemmer

    Metoder
    Realisering

    Konto

    //////////////////////////////////////////////////////
    // Konstruktører og destruktør

    /*
     * Standard konstruktør som setter en start-tilstand.
     */
    Konto::Konto() {
       saldo = 0.0;
    }

    /*
     * Kopikonstruktør som gjør et nytt objekt til en kopi av k.
     */
    Konto::Konto( const Konto& k ) {
       saldo = k.saldo;
       kontonummer = k.kontonummer;
    }

    /*
     * Destruktør som rydder opp.
     */
    Konto::~Konto() {
    }
     

    //////////////////////////////////////////////////////
    // Tilgangsmetoder

    /*
     * Henter kontonummeret.
     */
    Streng Konto::hentKontonummer() const {
       return kontonummer;
    }

    /*
     * Setter kontonummeret.
     */
    void Konto::settKontonummer( const Streng& nr ) {
       kontonummer = nr;
    }

    /*
     * Henter saldoen.
     */
    double Konto::hentSaldo() const {
       return saldo;
    }

    /*
     * Setter saldoen.
     */
    void Konto::settSaldo( double s ) {
       saldo = s;
    }

    //////////////////////////////////////////////////////
    // Andre metoder

    /*
     * Viser innholdet av konto-objekt på cout.
     */
    void Konto::vis() const {
       cout << kontonummer << " " << saldo << endl;
    }

    /*
     * Leser innhold til konto-objekt fra cin.
     */
    void Konto::vis() const {
       cout << "Oppgi kontonummer og saldo: ";
       cin >> kontonummer >> saldo; cin.ignore();
    }

    /*
     * Sjekker om konten er overtrukket. Returnerer sant hvis den
     * er overtrukket.
     */
    bool Konto::erOvertrukket() const {
       return saldo < 0;
    }

    /*
     * Sjekker om kontoen har kontonummeret nr. Returnerer sant hvis
     * kontonumrene er de samme.
     */
    bool Konto::erLik( const Streng& nr ) const {
       return nr == kontonummer;
    }

    Arkiv

    //////////////////////////////////////////////////////
    // Konstruktører og destruktør

    /*
     * Standard konstruktør som setter en start-tilstand.
     */
    Arkiv::Arkiv() {
       antall = 0;
    }

    /*
     * Kopikonstruktør som gjør et nytt objekt til en kopi av a.
     */
    Arkiv::Arkiv( const Arkiv& a ) {
       // implementeres ikke da det kun skal finnes ett arkiv-objekt
       // deklarasjonen må gjøres privat
    }

    /*
     * Destruktør som rydder opp etter arkivet.
     */
    Arkiv::~Arkiv() {
       for( int i = 0; i < antall; i++ )
          delete arkiv[i];
    }

    //////////////////////////////////////////////////////
    // Andre metoder

    /*
     * Setter inn en ny konto i arkivet.
     */
    void Arkiv::settInn( Konto* k ) {
       arkiv[antall] = k;
       antall++;
    }

    /*
     * Finner konto med kontonummeret nr og returnerer kontoen.
     */
    Konto* Arkiv::finn( const Streng& nr ) {
       // Søk gjennom hele arkivet
       for( int i = 0; i < antall; i++ )

          // Hvis konto i har samme kontonummer som nr
          if( arkiv[i]->erLik( nr ) )

           // Avslutt søkingen og metoden og returner konto i
             return arkiv[i];

       return 0; // returnerer nullpeker hvis nr ikke er funnet
               // merk at denne setningen kun utføres hvis
               // kontonummeret vi søker etter ikke finnes
    }

    /*
     * Sletter konto med kontonummeret nr.
     */
    void Arkiv::slett( const Streng& nr ) {
       // Søker gjennom arkivet
       for( int i = 0; i < antall; i++ ) {

          // Hvis konto nr i har kontonummeret nr
          if( arkiv[i]->erLik( nr ) ) {
             delete arkiv[i]; // Slett kontoen

           // Flytt kontoene etter konto i frem en plass i tabellen
             for( int j = i+1; j < antall; j++ )
                arkiv[j-1] = arkiv[j];

             antall--; // Reduser antallet med en

             return; // Avslutt søkingen og metoden
          }
       }
    }

    /*
     * Viser alle kontoene i arkivet.
     */
    void Arkiv::vis() {
       cout << "Saldoene i arkivet:" << endl;
       for( int i = 0; i < antall; i++ )
          arkiv[i]->vis();
    }


    Brukerinteraksjonen

    Nå gjenstår spørsmålet om hvordan kommandoene skal komme fra bruker og oversettes til de tidligere beskrevne funksjonene slik at resultatene kan vises.

    Ettersom dette skal skje mot et tekstbasert brukergrensesnitt, lager vi nå en meny. Menyen består av en del som for hvert valg viser menyvalgene, leser inn et valg og til slutt utfører funksjonen og viserresultatene. Da dette er en ren funksjonell inndeling, bruker vi ikke en klasse for menyen, men deler opp i funksjoner:


    Hovedprogrammet

    void main() {
       Arkiv arkiv;
       bool avslutt = false;
       do {
          visMeny();
          char kommando = lesKommando();
          avslutt = utforKommando( kommando, arkiv );
       } while( !avslutt );
    }

    Vis Meny

    /*
     * Viser aktuelle menyvalg
     */
    void visMeny() {
       cout << endl;
       cout << "Arkiv av konti" << endl;
       cout << "Kommandoer" << endl;
       cout << "n - Ny konto" << endl;
       cout << "f - Finn konto" << endl;
       cout << "s - Slett konto" << endl;
       cout << "e - Endre saldo på konto" << endl;
       cout << "o - Er konto overtrukket" << endl;
       cout << "v - Vis arkivet" << endl;
       cout << "a - Avslutt" << endl;
       cout << endl;
    }

    Les Kommando

    /*
     * Leser og returnerer en kommando.
     */
    char lesKommando() {
       char kommando;
       do {
          cout << "Kommando: ";
          cin >> kommando; cin.ignore();
       } while( kommando != 'n' && kommando != 'N' &&
                kommando != 'f' && kommando != 'F' &&
                kommando != 's' && kommando != 'S' &&
                kommando != 'e' && kommando != 'E' &&
                kommando != 'o' && kommando != 'O' &&
                kommando != 'v' && kommando != 'V' &&
                kommando != 'a' && kommando != 'A'
       );

       return kommando;
    }

    Utfør kommando og vis resultatet

    /*
     * Utfører en kommando og returnerer sann hvis avslutt-kommando.
     */
    bool utforKommando( char kommando, Arkiv& arkiv ) {
       Konto* konto;
       Streng kontoNr;
       double saldo;
       bool avslutt = false;

       switch( kommando ) {

    // Sett inn ny konto i arkivet
          case 'n':
          case 'N':
             cout << "Lag ny konto og sett inn i arkivet" << endl;
             konto = new Konto;
             konto->les();
             arkiv.settInn( konto );
             break;

    // Finn konto i arkivet
          case 'f':
          case 'F':
             cout << "Finn konto" << endl;
             cout << "Oppgi kontonummer: ";
             cin >> kontoNr; cin.ignore();
             konto = arkiv.finn( kontoNr );
             if( konto == 0 )
                cout << "Kontonummer ikke funnet" << endl;
             else {
                cout << "Konto funnet:" << endl;
                konto->vis();
             }
             break;

    // Slett konto i arkivet
          case 's':
          case 'S':
             cout << "Slett konto" << endl;
             cout << "Oppgi kontonummer: ";
             cin >> kontoNr; cin.ignore();
             arkiv.slett( kontoNr );
             break;

    // Endre saldo på konto
          case 'e':
          case 'E':
             cout << "Endre saldo på konto" << endl;
             cout << "Oppgi kontonummer: ";
             cin >> kontoNr; cin.ignore();
             konto = arkiv.finn( kontoNr );
             if( konto == 0 )
                cout << "Kontonummer ikke funnet" << endl;
             else {
                cout << "Oppgi ny saldo:" << endl;
                cin >> saldo; cin.ignore();
                konto->settSaldo( saldo );
             }
             break;

    // Sjekk om en konto er overtrukket
          case 'o':
          case 'O':
             cout << "Er konto overtrukket" << endl;
             cout << "Oppgi kontonummer: ";
             cin >> kontoNr; cin.ignore();
             konto = arkiv.finn( kontoNr );
             if( konto == 0 )
                cout << "Kontonummer ikke funnet" << endl;
             else {
                if( konto->erOvertrukket() )
                   cout << "Kontoen er overtrukket" << endl;
                else
                   cout << "Kontoen er ikke overtrukket" << endl;
             }
             break;

    // Vis arkivet
          case 'v':
          case 'V':
             arkiv.vis();
             break;

    // Avslutter
          case 'a':
          case 'A':
             avslutt = true;
             break;
       }

       return avslutt;
    }