I-PROGR2-HOME

  1. Einführung

  2. Die 'Mensa-Connection'; srachliche Beschreibung des Problems

  3. OO-Analyse mit UML

    1. UML-Klassen

    2. UML-Interaktion

  4. Implementierung; hier C++

    1. Eröffnen eines Projektes

    2. C++-Klassen

    3. C++-Implementierung

    4. C++-Usage

    5. Test

  5. Testfragen und Aufgaben


I-PROGR2 SS03 - PROGRAMMIEREN2 - Vorlesung mit Übung
OO-Analyse 'Mensa-Connection'

 Achtung : Skript gibt den mündlichen Vortrag nicht vollständig wieder !!!
 Skript ist noch nicht abgeschlossen !!
                         

AUTHOR: Gerd Döben-Henisch
DATE OF FIRST GENERATION: April-15, 2003
DATE OF LAST CHANGE: April-18, 2003,10:50h
EMAIL: Gerd Döben-Henisch



1. Einführung


Nach der ersten Konfrontation mit den 'typischen' C++-Klasseneigenschaften zeigt sich, dass die überwältigende Mehrheit mit dieser 'neuen Art zu Denken' noch erhebliche Probleme hat. Wir werden daher in dieser Vorlesung die einzelnen Schritte einer objektorientierten Programmierung (OO-Analyse mit UML, Implementierung in C++) nochmals anhand eines Beispiels illustrieren. Darauf aufbauened werden wir dann in den kommenden Vorlesungen weitere technische Details von C++ vorstellen.

Hier also jetzt die Rekonstruktion eines Beispiels mit allen bislang vorgestellten methodischen Schritten.

  1. Sprachliche Fassung des Problems


  2. Objektorientierte Analyse des Problems in UML


    1. Präzisierung der Hypothese mittels UML-Klassendiagrammen und Use-Case.


    2. Präzisierung mittels UML-Interaktionsdiagramm.


  3. Implementierung der OO-Struktuen in eine Sprache, hier C++


    1. Anlegen eines Projektes mit Namensvergabe (unter Linux im einfachen Fall ein Makefile)


    2. Übersetzung der UML-Klassen in C++-Klassen; Interface (Classenname.hpp)


    3. Definition der C++-Klassen in Implementierungsdateien (Classenname.cpp)


    4. Übersetzung des UML-Users und des Interaktionsdiagramms in eine Usage-Datei (Use_Projektname.cpp)


    5. Test



START



2. Die 'Mensa-Connection'; sprachliche Fassung des Problems


Bei 'richtigen' SW-Projekten ist die sprachliche Fassung sebst eine eigenständige, z.T. sehr aufwendige Arbeit, die neben den eigentlichen Anforderungen ('requirements') sehr viel fachliches Wissen ('Fachkonzept') aufbieten muss, um das Problem überhaupt adäquat darstellen zu können. Dies kann bisweilen viele Monate erfordern und hat nicht selten zum Ergebnis, dass ein Problem als 'nicht machbar' eingestuft wird. Hier jetzt also ein 'Minibeispiel'.

('Die Mensa-Connection'): Ausgangspunkt ist die Mensa der FH Frankfurt, deren Betrieb jedem aus eigener Erfahrung bekannt ist. Es sollen hier allererste Überlegungen angestellt werden, wie man dieses tägliche Geschehen modellieren kann. Erster Ansatzpunkt soll sein, dass man das Eintreten und wieder austreten aus der Mensa erfassen will unter Berücksichtigung der individuellen Verweilsdauer.Auf der einen seite werden also die Klienten ('Clients') angenommen, die die Dienste der Mensa nutzen wollen, auf der anderen Seite die Mensa ('Mensa') mit ihren Diensten. Auf der Klientenseite soll zunächst nur die absolute Zahl Population ('population') angenommen werden zusammen mit irgendeiner Art von Identifizierung ('identity'). Täglich fällt ein Teil dieser Population die Entscheidung Ja ('yes'), durch die eine Untergruppe der Entschiedenden ('decided') gebildet wird, also diejenigen, die tatsächlich die doenste der Mensa in Anspruch nehmen will. Als Dienste, die die Mensa anbietet, soll einmal angenommen werden, dass man in die Mensa einzutreten kann ('enter'). Dies kann scheitern, wenn alle Plätze ('max_places') der Mensa aktuell besetzt sind. Wer eingetreten ist, bekommt den Status eines Anwesenden ('present'), der in Abhängigkeit von einer Aufenthaltszeit ('duration') die Mensa wieder verlässt ('exit'), wenn diese seine individuelle Aufenthaltszeit abgelaufen ist ('duration = 0'). Es wird angenommen, dass jemand, der die Mensa verlässt, wieder Mitglied ('reenter') der Menge population der Klienten wird. soweit die sprachliche Beschreibung.


START



3. OO-Analyse mit UML


Für die folgende OO-Analyse benutzen wir UML-Diagramme in einer vereinfachten Form; es genügt, die grobe Struktur zu erfassen. Details werden im Kontext der Implementierung erarbeitet.


START



3.1 UML-Klassen


In unserem Fall können wir erste Hypothesen über mögliche beteiligte Klassen und deren Eigenschaften bilden, ohne schon zu viele Details über diese Klassen zu wissen. Da keine solche Analyse 'zwingend' ist, lassen sich hier sicher auch andere Lösungen vorstellen. einige dieser Fragen diskutieren wir im Kontext der Implementierung. Im 'Ernstfall' müsste man versuchen, diese Detaildiskkussion, die ja sachliche Aspekte des zu behandelnden Problems betrifft, soweit wie möglich im Fachkonzept vorwegzunehmen.



umlclass

Erste Hypothesen über beteiligte Klassen




START



3.2 UML-Interaktion


Die Existenz möglicher Objekte (als Instantiierungen von Klassen) sagt noch nicht allzuviel darüber aus, wie die verfügbaren Objektfunktionen (Operationen/ Methoden) ineinandergreifen: wann ruft wer in welcher abfolge welche Funktionen auf? Dies muss in einem Interaktionsdiagramm geklärt werden..



umlint

Interaktionsdiagramm für Mensa-Connection




START



Dieses --vereinfachte-- Interaktionsdiagramm geht also davon aus, dass in einer Initialisierungsphase für ein client-Objekt festgelegt wird, wieviele Mitglieder die Population umfasst, aus der heraus sich mittels der c:yes()-Funktion eine Untergruppe von solchen Mitgliedern bildet, die in die Mensa gehen wollen. Für ein Mensa-Objekt wird festgelegt, dass die maximale Anzahl der Plätze sowie die aktuell verfügbaren Plätze initialisiert werden sollen.

Nach der Initialisierung beginnt der eigentliche Prozessablauf (hier als 'RUN' bezeichnet). Ein bestimmter Anteil der Population der Klienten entscheidet sich (c:yes()), in die Mensa zu gehen (die Menge c:population nimmt ab, die Menge c:decided nimmt zu). Die 'Entschlossenen' wollen mit m:enter in die Mensa. Sind schon alle Plätze besetzt, dann soll die Aktion m:enter() scheitern, andernfalls werden in der Mensa Plätze besetzt (m:actual_places wird vermindert) und die Menge der Entschiedenen nimmt ab. Nach einem zu vereinbarenden Rhythmus muss die Menge der Zeitkontingente mittels m:update() vermindert werden. Ist bei einigen das Zeitkontingent bei 0 angekommen, können diese mittels m:exit() die Mensa wieder verlassen: die Anzahl der verfügbaren Plätze nimmt wieder zu und die Stärke der Population der Klienten wächst.

Anmerkung zur Syntax: die Schreibweise 'c:Clients' besagt in UML, dass 'c' ein Objekt der Klasse 'Clients' ist, entsprechend 'm:Mensa', dass 'm' ein Objekt der Klasse 'Mensa' ist. Werden dann Variablennamen (Attributnamen) oder Funktionsnamen (Operations-/Methodennamen) angeführt (wie z.B. c:yes()), muss man immer den Namen des Objektes mit einem Doppelpunkt voranstellen, damit klar ist, zu welchem Objekt diese Variablen bzw. Funktionen gehören.

4. Implementierung; hier C++


Nach der vorangehenden Strukturierung des Problems entsprechend einer OO-Analyse kommt irgendwann die Phase der Umsetzung (Implementierung) der abstrakten objektorientierten Konzepte in eine konkrete, lauffähige Programmiersprache. Im Prinzip kann dies jede Programmiersprache sein. Handelt es sich um eine sogenannte objektorientierte Programmiersprache, dann ist die Umsetzung umso einfacher, je mehr die objektorientierte Programmiersprache alle die Mittel bereitstellt, die in der objektorientierten Analyse benutzt werden. C++ ist eine objektorientierte Programmiersprache, die eine fast 1-zu-1-Übersetzung erlaubt.


START



4.1 Eröffnen eines Projektes


Der Übergang von einer OO-Analyse mit UML-Sprachmitteln in eine C++-Implementierung lässt sich grob wie folgt veranschaulichen (siehe Schaubild):



umlc++

Von UML in ein C++-Projekt



Die UML-Klassendiagramme werden direkt (fast 1:1) in C++Klassendiagramme übersetzt. Bei Klassendefinitionen handelt es sich aber fast ausschliesslich um 'leere Hülsen', 'Schablonen', 'Grundrisse', die zwar die allgemeine Idee der Struktur kommunizieren, sämtliche technischen Details des 'Wie' aber noch offenlassen. Diese werden in speziellen 'C++Implementierungsdateien' festgelegt. Es ist dieser Übergang von den Klassendefinitionen zur Implementierung, in dem das sprachspezifische Knowhow zum Tragen kommt bzw., wenn es nicht vorhanden ist, das Projekt ins Stocken gerät.

Hat man die C++-Klassen implementiert, dann ist damit noch nichts über den eigentlichen Prozess gesagt, in dem diese Klassen genutzt werden sollen. Man muss also analog dem UML-Iteraktionsdiagramm ein C++-Programm schreiben --im folgenden immer C++-Usage-Programm genannt-- , in dem das Auftreten und die Interaktion der eingeführten Klassen in Form von Objekten beschrieben wird. Sofern man keine parallelen Prozesse darstellt, könnte man die Implementierung des UML-Interaktionsdiagramms im Rahmen eines C++-Usage-Programms auch mittels eine klassischen Struktogramms vorbereiten. Denn letztlich handelt es sich bei dem C++-Usage-Programm um nichts anderes als einem sequentiellen Prozess, in dem Variablen und Funktionen von zuvor eingeführten Objekten aufgerufen werden. Auf dieser Ebene gibt es keinen Unterschied zu einem 'klassischen nicht-objektorientierten' Programm.

Dabei hat sich folgende Namenskonvention eingebürgert:

Für die Verwaltung der Dateien im Rahmen eines Projektes wird unter Unix/Linux in der Regel das sehr erprobte und überaus mächtige make-Tool benutzt. Basis der Anwendung von make ist eine sogenannte make-Datei mit dem Namen Makefile; dies muss die einzige derartige Datei im Projektordner sein (nähere Angaben zu den umfangreichen Möglichkeiten von make entnehme man bitte der entsprechenden info-Datei unter Unix/Linux).

Hier eine sehr einfache make-Datei für unser Mini-Projekt:


#************************
#
# Makefile
#
# for Mensaconnection
#
#*********************************


objects = use_mensaconnection.o Mensa.o

use_mensaconnection: $(objects)
	g++ -o use_mensaconnection $(objects)

use_mensaconnection.o: use_mensaconnection.cpp  Mensa.hpp
	g++ -c use_mensaconnection.cpp

Mensa.o: Mensa.cpp Mensa.hpp
	g++ -c Mensa.cpp


clean:
	rm use_mensaconnection $(objects)

In der ersten Zeile wird die Variable objects definiert und dieser Variablen wird als Wert die Liste derjenigen Objektdateien zugewiessen, der die zu diesem Zeitpunkt im Projekt benutzt werden. Wie man sieht, ist das Objekt Clients an dieser Stelle noch nicht definiert, sondern nur Mensa zusammen mit einer Usage-Datei.

In den folgenden Zeilen wird dann jeweils eine Objektdatei in Abhängigkeit von anderen Dateien einzeln vorkompiliert (Option -c). Die Zieldatei (Option -o )wird dann in Abängigkeit von allen Objektdateien erzeugt.

Für make existieren zahlreiche weitere technische Möglichkeiten, auf die wir hier noch nicht eingehen. Ein Projektverzeichnis zu Mensaconnection könnte wie folgt aussehen:

drwxr-xr-x    2 gerd     users         240 Apr 17 20:16 ./
drwxr-xr-x    7 gerd     users         168 Apr 15 21:39 ../
-rw-r--r--    1 gerd     users          66 Apr 15 22:31 Clients.cpp
-rw-r--r--    1 gerd     users         354 Apr 15 22:37 Clients.hpp
-rw-r--r--    1 gerd     users         398 Apr 16 11:01 Makefile
-rw-r--r--    1 gerd     users        2657 Apr 16 11:09 Mensa.cpp
-rw-r--r--    1 gerd     users         905 Apr 16 11:07 Mensa.hpp
-rw-r--r--    1 gerd     users        1193 Apr 16 11:04 use_mensaconnection.cpp

Die Anwendung von Make würde dann wie folgt aussehen:

gerd@goedel:~/WEB-MATERIAL/fh/I-PROGR2/I-PROGR2-EX/EX6> make
g++ -c use_mensaconnection.cpp
g++ -c Mensa.cpp
g++ -o use_mensaconnection use_mensaconnection.o Mensa.o

Auf der Befehlszeile der shell übergibt man 'make' und dann bearbeitet make die Dateien, so, wie sie im Makefile aufgeführt werden. Wie man sieht, gibt es im Ordner aktuell schon mehr Dateien als im Makefile, es werden nur die Dateien bearbeitet, die explizit im Makefile stehen. Nach der anwendung von make existiert dann zusätzlich die Zieldatei use_mensaconnection.

gerd@goedel:~/WEB-MATERIAL/fh/I-PROGR2/I-PROGR2-EX/EX6> l
insgesamt 144
drwxr-xr-x    2 gerd     users         344 Apr 17 20:19 ./
drwxr-xr-x    7 gerd     users         168 Apr 15 21:39 ../
-rw-r--r--    1 gerd     users          66 Apr 15 22:31 Clients.cpp
-rw-r--r--    1 gerd     users         354 Apr 15 22:37 Clients.hpp
-rw-r--r--    1 gerd     users         398 Apr 16 11:01 Makefile
-rw-r--r--    1 gerd     users        2657 Apr 16 11:09 Mensa.cpp
-rw-r--r--    1 gerd     users         905 Apr 16 11:07 Mensa.hpp
-rw-r--r--    1 gerd     users       54124 Apr 17 20:19 Mensa.o
-rwxr-xr-x    1 gerd     users       45496 Apr 17 20:19 use_mensaconnection*
-rw-r--r--    1 gerd     users        1193 Apr 16 11:04 use_mensaconnection.cpp
-rw-r--r--    1 gerd     users       13932 Apr 17 20:19 use_mensaconnection.o

START



4.2 C++-Klassen


Die ersten Dateien, die in C++ von UML umgesetzt werden sollen, das sind die Klassendateien. Hier kann man die UML-Attribute direkt in C++-Variablen übersetzen und die UML-Operatoren/ Methoden direkt in C++-Klassen-Element-Funktionen. Für die Klasse Mensa sei dies gezeigt:




//----------------------
//
// Mensa.hpp
//
// Author: gerd d-h
// First: April-15, 2003
// Last: April-17, 2003
//
// Compilation: make
// usage: mensaconnection
//
//-----------------------------

#ifndef Mensa_HPP
#define Mensa_HPP

#include<map>

class Mensa {

private:

  int max_presence;      //Maximal number of places in Mensa

  std::multimap<int,int> mpresence; //Generate object mpresence for mensa
                                    // mpresence is a multimap with duration time 
                                    //as key and identity as value

public:

  Mensa(int);

  bool enter(int,int);  //Enter a client in Mensa
  void update(int);     //update duration-time of every client
  int exit(int);     //single client with duration-time n and gives back identity
  void exit_all(int);      //exit all clients with duration-time n
  int toleave(int);   //checks sum of all clients to be ready to leave
  void show_state();  //Shows actual state of mensa

};



#endif



Trotz der unübersehbaren Ähnlichkeit zwischen der UML-Klasse Mensa und der C++-Klasse gibt es auch Unterschiede. Ein wichtiger Unterschied ist der Konstruktor Mensa(int) in der C++-Klasse. Man kann Konstruktoren auffassen als Schnittstelle zwischen Klasse und Objektinstantiierung. In den Konstruktoren einer Klasse --es kann mehr als einen geben-- kann der Software-Architekt der Klasse festlegen, welche Massnahmen während der Initialisierung eines Objektes der Klasse getroffen werden sollen. Im Falle der Klasse Mensa gibt es nur einen Konstruktor.

Der nächste auffällige Unterschied zur UML-Klasse ist die Einführung eines Objektes mpresence vom Typ multimap (Siehe Details im C++-Standard, S.493ff. Eine Multimap gilt in C++ als Beispiel eines assoziativen Containers.) mit den Multimap-Typen < int, int>. multimap ist selbst eine Klasse und die Variable mpresence damit eine Instantiierung dieser Klasse, also ein Objekt. Dass solch ein Attribut in der UML-Klasse nicht auftritt ist kein prinzipielles Problem, sondern liegt nur daran, dass die vorgestellte Definition der UML-Klasse nicht vollständig ist. Die Einführung dieser Variablen in der C++-Klasse resultiert daraus, dass es sich im Zusammenhang mit der Implementierung der C++-Element-Funktionen gezeigt hat, dass die Hinzuziehung der Datenstruktur Multimap --intern ein balanzierter binärer Suchbaum- die Formulierung des Problems vereinfacht. Man kann es auch so formulieren, für die Implementierung der Funktionen enter(), update() und exit() erweist es sich als vorteilhaft, wenn man eine Datenstruktur vom Typ multimap zur Verfügung hat.

Die gegenüber der UML-Klasse Mensa zusätzlichen Funktionen exit_all(), toleave() sowie show_states() rühren daher, dass in der C++-Version einfach noch ein paar 'nützliche' Hilfsfunktionen zusätzlich definiert wurden.

Die Einzelheiten all dieser Funktionen werden im Zusammenhang der Implementierung erklärt.


START



4.3 C++-Implementierung


Wie mehrfach betont, handelt es sich bei deiner Klassendefintion in der Regel um eine leere Hülse, eine Schablone, aus der man für gewöhnlich --von sogenannten Inline-Definitionen mal abgesehen-- nichts über die Details der Umsetzung entnehmen kann. Diese Informationen finden sich in der/den Implementierungsdatei(en). Am Beispiel der Implementierungsdateien zur Klasse Mensa sei dies verdeutlicht.


//--------------------------
//
// Mensa.cpp
//
// Author: gerd d-h
// First: April-15, 2003
// Last: April-17, 2003
//
// Compilation: make
// usage: mensaconnection
//
//-----------------------------


#include "Mensa.hpp"
#include <iostream>
#include<map>

//----------------------------------------------------------
Mensa::Mensa(int mpr = 1)
{
  cout << "ENTER NUMBER OF MAX.PLACES IN MENSA = ";
  cin >> max_presence;
}

//---------------------------------------------------------------
bool Mensa::enter(int dur,int id) {

  if (  mpresence.size()  >=  max_presence) { return false; }

  else {
  mpresence.insert(std::pair<int,int>(dur,id));
  return true;
  } //end else = true

}

//-----------------------------------------------------------------
void Mensa::update(int decrement){

  int dur, id;

std::multimap<int,int>::iterator pos;

 for(pos = mpresence.begin(); pos != mpresence.end(); ++pos) {

   if ( pos->first > 0 ) {
           dur = pos->first;
	   id = pos->second;
	   if( (dur - decrement) < 0 ) { dur = 0; }
	   else{ dur -= decrement; }
	   mpresence.erase(pos);
           mpresence.insert(std::pair<int,int>(dur,id));
    }//end if = pos->first
 }// end for = pos mpresence.begin
}

//-------------------------------------------------------------------------
int Mensa::exit(int duration){

  int identity;

  std::multimap<int,int>::iterator pos;

  pos = mpresence.find(duration);
  if( pos != mpresence.end() ) {

    identity = pos->second;
    mpresence.erase(pos);

    return identity;
  }

  return -1;

}

//----------------------------------------------------------------------------
void Mensa::exit_all(int duration){


  int counter1, counter2;
  counter2 = 0;

  counter1 = mpresence.count(duration);

  cout << "NUMBER OF CLIENTS WITH DURATION BEFORE "<< duration << " = " << counter1 << endl;

  std::multimap<int,int>::iterator pos;

  for ( int i=1; i<= counter1; i++) {
  pos = mpresence.find(duration);
  if( pos != mpresence.end() ) { mpresence.erase(pos); counter2++; }
  }


  counter1 = mpresence.count(duration);

  cout << "NUMBER OF CLIENTS WITH DURATION AFTER "<< duration << " = " << counter1 << endl;

  cout << "COUNTED ERASIONS "<< counter2 << endl;
}

//-----------------------------------------------------------------------------------------
int Mensa::toleave(int duration){

  return mpresence.count(duration);

}


//----------------------------------------------------------------------
void Mensa::show_state(){

 std::multimap<int,int>::iterator pos;

  cout << "SHOW MENSA ACTUAL STATES -------------------------------"<< endl;
  cout << "MAX-POSSIBLE Clients = "<< mpresence.max_size() << endl;
  cout << "THEORETICALLY ALLOWED MAX.Clients = "<<  max_presence <<endl;
  cout << "ACTUAL Clients = " << mpresence.size() << endl;
  cout << "LIST OF ALL PRESENCES:= " << endl;

  for(pos = mpresence.begin(); pos != mpresence.end(); ++pos){

    cout << "duration = "<< pos->first << " identity = "<< pos->second<< endl;
  }


}



Als erstes wird der Konstruktor Mensa() implementiert. Der doppelte Doppelpunkt mit dem vorangestellten 'Mensa' --Mensa::Mensa(int mpr = 1)-- besagt, dass die Funktion Mensa() eine Element-Funktion der Klasse Mensa ist. Es gehört zur Besonderheit der Konstruktor-Funktion --siehe auch vorausgehende Vorlesung--, dass diese keinen Rückgabewert hat. Die Arbeit des Konstruktor Mensa() besteht im vorliegenden Beispiel darin, den Benutzer zu fragen, wieviele maximale Plätze die Mensa haben soll. Die Antwort des Benutzers wird dann der Variablen max_places der Klasse Mensa zugewiessen.

Dann wird die Element-Funktion bool Mensa::enter(int dur,int id) implementiert.

Die Element-Funktion enter() löst zwei Aufgaben. (i) Zunächst prüft sie anhand der Variablen max_presence, ob die aktuell verfügbare Präsenzzahl mit mpresence.size() ausgeschöpft ist (falls nicht, dann kann man nicht 'eintreten'), (ii) falls ja, dann wird ein neues Element in die Mensa eingefügt (mpresence.insert(std::pair<int,int>(dur,id));). Das neue Element enthält eine Verweilzeit ('dur' := duration) und eine Identität ('id' := identity). Dabei wird der Operator 'pair' benutzt (Für Details siehe C++-Standard, S.358f). Der Operator pair<,>(,) nimmt zwei Argumente und setzt sie als Paar in das Objekt ein, das zuvor genannt worden ist, hier das Objekt mpresence vom Typ multimap.

Die Element-Funktion void Mensa::update(int decrement) hat die Aufgabe, für alle aktuell in der Mensa befindlichen Klienten ihre individuelle Verweilzeit um den Faktor decrement zu vermindern. Alle diejenigen Klienten, deren Verweilzeit daurch auf 0 sinkt, sind dann Kandidaten, die Mensa zu verlassen. Um die Verweilzeit 'duration' für jedes Element vermindern zu können, muss die gesamte Menge durchlaufen werden. Dies geschieht mit Hilfe eines sogenannten Iterator-Objektes pos (Für Details siehe C++-Standard, S.509ff). Ein Iterator stellt eine Verallgemeinerung des Pointer-Konzeptes dar; mit Iteratoren ist es möglich, über Objekte unterschiedlichsten Typs die üblichen Pointeroperationen (Wert auslesen, Wert einschreiben) auszuführen. Im vorliegenden Fall wird ein Iterator-Objekt pos so definiert, dass es auf das Objekt vom Typ multimap anwendbar ist. Damit ergibt sich die Möglichkeit, die Elemente der Multimap einzeln abzusuchen: std::multimap<int,int>::iterator pos;. Da im Rahmen der Klasse multimap speziell die Iteratoren begin() und end() definiert sind, kann man mit dem Iterator-Objekt pos unter Zugriff auf begin() und end() eine Schleife definieren, in der pos alle Elemente des Objektes mpresence vom 'Anfang' bis 'Ende' durchläuft: for(pos = mpresence.begin(); pos != mpresence.end(); ++pos). Soll jetzt bei einem Klienten in der Mensa die Verweilzeit vermindert werden, da sie noch nicht 0 ist, dann gilt es, im Falle von maps (und auch sets!) zu beachten, dass man nicht einfach die Key-Werte überschreiben darf, da diese ja einer internen Verwaltung unterliegen; würde man diese 'übergehen', dann würde die Anordnung der Keys in der Datenstruktur nicht mehr stimmen. Man muss daher so vorgehen, dass man die Werte des Elementes, dessen Werte man ändern will, erst zwischenspeichert, dann das alte Element 'offiziell' löscht ( mpresence.erase(pos); ) und dann 'ofiziell' ein neues Element mit den zwischengespeicherten --und modifizierten-- Werten wieder einsetzt ( mpresence.insert(std::pair<int,int>(dur,id)); ).

Die Element-Funktion int Mensa::exit(int duration) hat die aufgabe, alle Klienten mit der Verweilzeit 0 aus der Mensa wieder zu entfernen. Dabei soll sie als Rückgabewert die Identität des Klienten zurückliefern. Um einene Klienten mit der Verweilzeit 0 in der Mensa zu finden, bedient sich die Funktion Exit wieder einem Iterator-Objekt pos, dieses Mal aber nicht im Kontext einer Suchschleife über alle Elemente, sondern unter Verwendung der speziellen find-Funktion der multimap-Klasse: pos = mpresence.find(duration); Die in der Klasse multimap 'eingebaute' Funktion 'find' sucht das erste Element, dessen Key den Wert duration besitzt. Die Identität ('identity') dieses Elementes wird zurückgeliefert und das Element wird gelöscht. In der aktuellen Version ist es Aufgabe des usage-Programms, dafür zu sorgen, dass alle Elemente mit der Verweilzeit 0 aus der Mensa entfernt werden.

Die Funktion int Mensa::toleave(int duration) liefert mit Hilfe der eingebauten multimap-Funktion 'count()' die Anzahl aller Elemente zurück, deren Key-Wert den Wert 'duration' besitzt --im konkreten Fall eben die 0--.

Schliesslich hilft die Funktion void Mensa::show_state() die aktuellen Werte des Objektes Mensa anzuzeigen.

Die Funktion exit_all() ist hier nicht von Bedeutung; sie hat nur experimentellen Charakter.


START



4.4 C++-Usage


In der Usage-Datei sollen nun die zuvor definierten Elemente benutzt werden. Als 'Leitfaden' für die Nutzung dient hier speziell das UML-Interaktionsdiagramm, in dem festgelegt ist, welches Objekt wann von wem welche Leistungen abruft. Da das Interaktionsdiagramm im Rahmen einer sequentiellen Verarbeitung nur durch Hintereinanderausführen der einzelnen Befehle möglich ist, kann man im sequentiellen Fall ein Interaktionsdiagramm direkt in ein Struktogramm überführen. Die vereinfachte Version solch eines Interaktionsdiagramms --der Initialisierugsteil wurde ausgelassen-- ist das folgende:



structuse

Grobstruktur eines Struktogramms zum UML-Intraktionsdiagramm



Man sieht, dass die Iteration des UML-Diagramms in eine Schleifenanweisdung überführt wurde und die Ausführung der einzelnen Operationen wurden als Aktionsblöcke aufgefasst, die hintereinander so angeordnet sind wie im Interaktionsdiagramm. Idealerweise sollte der Programmkode der Usedatei die Struktur dieses Struktogramms widerspiegeln (+ Initialisierung). Der nachfolgende Programmkode tut das noch nicht.


//---------------------------
//
// use_mensaconnection.cpp
//
// Author: gerd d-h
// First: April-15, 2003
// Last: april-17, 2003
//
//-----------------------------------------------------

#include <iostream>
#include "Mensa.hpp"
//#include "Clients.hpp"

using namespace std;

int main()
{
  char input;
  int duration, identity, k;


  input = 'y';

  Mensa m(1);  // Create Object Mensa with default number of places =1


  // Loop for entering clients into Mensa

  while(input == 'y') {

 cout << "IDENTITY = ";
    cin >> identity;

 cout << "DURATION = ";
    cin >> duration;

  if ( m.enter(duration, identity) ) { cout << "Entering succesful" << endl; }
  else { cout << "Entering not succesful" << endl; }


 cout << "Continue ? (y/n)";
 cin >> input;

  } // end while = enter

  m.show_state();

  //Update the duration-time for each client

  cout << "TO Leave = "<< m.toleave(0) << endl;


  m.update(3);   //Decrement duration-time by 3 time-units

  cout << "TO Leave after update = "<< m.toleave(0) << endl;
 m.show_state();

  k=m.toleave(0);
  for (int i=1; i<= k; i++){

    cout << "Client with id = " << m.exit(0) << " is back." << endl;
  }

  cout << "TO Leave after exit = "<< m.toleave(0) << endl;
 m.show_state();

    return 0;
}

Beispiel für Testlauf:

gerd@goedel:~/WEB-MATERIAL/fh/I-PROGR2/I-PROGR2-EX/EX6> ./use_mensaconnection
ENTER NUMBER OF MAX.PLACES IN MENSA = 5
IDENTITY = 3
DURATION = 3
Entering succesful
Continue ? (y/n)y
IDENTITY = 7
DURATION = 2
Entering succesful
Continue ? (y/n)y
IDENTITY = 6
DURATION = 3
Entering succesful
Continue ? (y/n)y
IDENTITY = 8
DURATION = 4
Entering succesful
Continue ? (y/n)y
IDENTITY = 9
DURATION = 3
Entering succesful
Continue ? (y/n)y
IDENTITY = 11
DURATION = 6
Entering not succesful
Continue ? (y/n)n
SHOW MENSA ACTUAL STATES -------------------------------
MAX-POSSIBLE Clients = 4294967295
THEORETICALLY ALLOWED MAX.Clients = 5
ACTUAL Clients = 5
LIST OF ALL PRESENCES:=
duration = 2 identity = 7
duration = 3 identity = 3
duration = 3 identity = 6
duration = 3 identity = 9
duration = 4 identity = 8
TO Leave = 0
TO Leave after update = 4
SHOW MENSA ACTUAL STATES -------------------------------
MAX-POSSIBLE Clients = 4294967295
THEORETICALLY ALLOWED MAX.Clients = 5
ACTUAL Clients = 5
LIST OF ALL PRESENCES:=
duration = 0 identity = 7
duration = 0 identity = 3
duration = 0 identity = 6
duration = 0 identity = 9
duration = 1 identity = 8
Client with id = 7 is back.
Client with id = 3 is back.
Client with id = 6 is back.
Client with id = 9 is back.
TO Leave after exit = 0
SHOW MENSA ACTUAL STATES -------------------------------
MAX-POSSIBLE Clients = 4294967295
THEORETICALLY ALLOWED MAX.Clients = 5
ACTUAL Clients = 1
LIST OF ALL PRESENCES:=
duration = 1 identity = 8
gerd@goedel:~/WEB-MATERIAL/fh/I-PROGR2/I-PROGR2-EX/EX6>
 

START



4.5 Test




START



5. Fragen und Aufgaben




START