Programmieren 2 Projekt FutureCar

Transcription

Programmieren 2 Projekt FutureCar
Hochschule Darmstadt
FB Informatik
Prof. Dr. R.Nitsch
Stand: WS 08
1.
2.
3.
4.
5.
Ziele:
Programmieren 2
Projekt FutureCar
Teil 5
Sie sollen verkettete Listen implementieren können.
Sie sollen das Iterator-Konzept verstehen, implementieren und anwenden können.
Sie sollen einen abstrakten Datentyp List anforderungsgemäß implementieren können.
Sie sollen Klassentemplates implementieren und anwenden können
Sie sollen den abstrakten Datentyp List sinnvoll einsetzen können.
Teilaufgabe 5.1 (ADT List)
1.
Implementieren Sie den Abstrakten Datentyp (ADT) List
wie in Anlage 1 gefordert als doppelt verkettete Liste. Die
mit "voluntarily" gekennzeichneten Operationen müssen
nicht implementiert werden. Ihre Implementierung kann
jedoch den Aufgabenteil 3 erheblich vereinfachen. Empfohlen wird eine Listenstruktur mit 1 oder 2 SentinelElementen (http://en.wikipedia.org/wiki/Linked_list)
2.
Testen Sie den ADT List mit der zur Verfügung gestellten
Testanwendung TestList. Beseitigen Sie alle gemeldeten
Syntax- und Laufzeit-Fehler.
Hinweise:
1.
Um nicht zusätzlich const-Iteratoren implementieren zu müssen, dürfen Sie das Prinzip des kleinsten Privilegs (auch const-correctness genannt) bei der Implementierung von class List bei Bedarf vernachlässigen.
2.
class TestList testet auch die als optional eingestufte Funktionalitäten der Klasse List. Wenn Sie diese nicht
implementieren, müssen Sie die zugehörigen Tests aus der Klasse ListTest auskommentieren.
Empfehlung: Die Kernfunktionalität des ADT List wird durch die Methoden insert und erase bereit gestellt. Implementieren Sie diese unbedingt zuerst. Die Implementation der restlichen Funktionen besteht dann im Wesentlichen aus einer Wiederverwendung der Kernfunktionen. Implementieren Sie diese in der durch die Tests vorgegebenen Reihenfolge. Beispiel: Methode pop_front() lässt sich durch die Anweisung "erase(begin());"
implementieren.
Teilaufgabe 5.2 (Template ADT List)
1.
Wandeln Sie den ADT aus Teilaufgabe 5.1 um in ein Klassen-Template. Orientieren Sie Ihren Entwurf an dem
Klassengerüst in Anlage 2.
2.
Ändern Sie die Testanwendung TestList so ab, dass Sie auch den Template-ADT testen kann.
3.
Testen Sie den Template ADT List mit der angepassten Testanwendung TestList. Beseitigen Sie alle gemeldeten Syntax- und Laufzeit-Fehler.
Teilaufgabe 5.3 (Anwendung des ADT List)
Im Projekt FutureCar werden mehrere Container verwendet. Einige von diesen sind zur Abdeckung von Anforderungen eingesetzt, die besser mit einem Listen-ADT zu erfüllen sind.
1.
Ersetzen Sie den Container Location route[MAXSIZE] in class Navi durch einen List-Container und
passen Sie die Navi-Implementation an.
2.
Wählen Sie mindestens 1 weiteren Container im FC-Projekt aus und ersetzen Sie diese(n) durch Ihren ListADT.
PG2-WS08-Teil5-Projekt FC.doc
Seite 1 von 5
Hinweise:
Wenn Sie in Ihrem FC-Projekt bereits Algorithmen der C++-STL verwenden, und diese nun List-Iteratoren übergeben bekommen, werden Sie Compiler-Fehlermeldungen erhalten wie z.B.
error C2039: 'iterator_category': Ist kein Element von 'List<T>::_Iter'
Dies liegt dann daran, dass alle STL-Algorithmen Container-Klassen und deren Iterator-Klassen bestimmte Anforderungen stellen. Die Algorithmen verwenden z.B. Stellvertreternamen für containerspezifische Datentypen
(Typ-Aliase) die von der Kontrollabstraktion, also den Iterator-Klassen der Container zur Verüfgung gestellt werden müssen. Aus diesem Grund sollte Ihre List::Iterator-Deklaration folgende eingeschachtelten TypAliase (nested types) bereit stellen, damit Ihr List-Container standardkonform wird und mit den STL-Algorithmen
kooperieren kann:
typedef
typedef
typedef
typedef
T value_type;
int difference_type;
T* pointer;
T& reference;
Darüber hinaus funktionieren manche Algorithmen mit einem Forward-Iterator, während andere Algorithmen
z.B. einen Random-Access-Iterator benötigen. Das STL-Konzept sieht hier vor, dass der Compiler bereits diese
Voraussetzungen überprüft. Dazu werden die Iterator-Klassen mit einer Marke (engl.: tag) versehen. Diese Marke müssen Sie ebenfalls in der Klasse List::iterator mit der Anweisung
typedef std::bidirectional_iterator_tag iterator_category;
setzen.
Folgende Markierungsklassen sind im Headerfile <iterator> vordefiniert:
struct input_iterator_tag { };
struct output_iterator_tag { };
struct forward_iterator_tag
: public input_iterator_tag { };
// Ein Forward-Iterator ist auch ein Input-Iterator
struct bidirectional_iterator_tag
: public forward_iterator_tag { };
struct random_access_iterator_tag
: public forward_iterator_tag { }; // Ein Random-Access-Iterator ist auch ein
// bidirectionaler Iterator
Für den Iterator der Liste3 aus der Vorlesung müsste die erste typedef-Anweisung durch
typedef std::forward_iterator_tag iterator_category;
ersetzt werden, weil dieser Iterator der Forward-Iterator-Kategorie angehört.
Weitergehende Informationen zu diesem Tagging-Konzept finden Sie in [Breymann, C++. S. 546ff]
PG2-WS08-Teil5-Projekt FC.doc
Seite 2 von 5
Anlage 1: Spezifikation der öffentlichen Schnittstelle des ADT List
//********* Public interface class List ***************
// Note: This interface specification complies with the std::list specification of
//
the C++ Standard but keep in mind that the C++ specification is much more
//
comprehensively
List::List();
// POST: size()==0
List::List( List& list );
// POST: *this == list
bool List::empty() const;
// returns true if size()==0
void List::clear()
//
a.clear() has same effect as a.erase(a.begin(), a.end())
//
post: size() == 0
T& List::front();
// a.front() and *a.begin() give the same result
T& List::back();
// PRE: size>0
// returns *(--end())
void List::push_front( const T& toPush );
// inserts value of toPush as first element in list
// a.push_front(toPush) has same effect as a.insert( a.begin(), toPush )
void List::pop_front();
// erases first element of list
// a.pop_front() has same effect as a.erase( a.begin(), toPush )
void List::push_back(const T& toPush);
// appends value of toPush to the end of the list
// a.push_back(toPush) has same effect as a.insert( a.end(), toPush )
void List::pop_back();
// a.pop_back() erases the element pointed to by --a.end()
void List::remove( const T& toRemove );
// Effects: Erases all the elements in the list referred by a list iterator i
// for which the following conditions hold: *i== value
List::_Iter List::insert( List::_Iter iter, const T& value ) throw(ListException);
// a.insert(p,t) inserts a copy of t before p
// The iterator returned from a.insert(p,t) points to the copy of t inserted into a.
// An object of type ListException is thrown if iter was not created by the list object
// invoking insert.
void List::insert(List::_Iter iter, size_type n, const T& value ) // voluntarily
// a.insert(p,t) inserts n copies of t before p
List::_Iter List::erase( List::_Iter& iter);
// a.erase(q) iterator erases the element pointed to by q
// The iterator returned from a.erase(q) points to the element immediately
// following q prior to the element being erased.
// If no such element exists, a.end() is returned.
// a.end() is returned if a.empty==true
List::_Iter List::erase(List::_Iter& position, List::_Iter& last) // voluntarily
// Erases the elements in the range [position, last).
// Returns iterator last or iterator end() if last doesn't exist
// (end() reached before last)
PG2-WS08-Teil5-Projekt FC.doc
Seite 3 von 5
void List::resize( size_type newsize , T value = T()) // voluntarily
/*
Effects:
if( newsize > size() )
// append newsize – this->size() copies of object value to the list
else if( newsize<size() ) {
// leave first newsize elements unchanged in List
// and delete all successor elements
}
else
; // do nothing
*/
List& List::operator=( List& rightOp );
// POST *this==rightOp
bool List::operator==( List& rightOp );
// returns true if a.size() == b.size()&& equal(a.begin(),a.end(), b.begin())
// equal(first1 ,last1, first2) returns true if for every iterator i in the range
// [first1 ,last1 ) the following condition holds:
// *i == *(first2 + (i - first1 )). Otherwise,returns false.
bool List::operator!=( List& rightOp );
// listA!=listB is equivalent to !(listA==listB)
//********* Public Interface class List::_Iter ***************
List::_Iter::_Iter( ListElem* pcur, List* plist );
T& List::_Iter::operator*() throw(ListException);
// iterators pointing to end() are not dereferenceable
// In this case an object of type ListException is thrown
T* List::_Iter::operator->() // voluntarily
// Effects: return &( operator *());
// or in other words returns a pointer to (**this)
List::_Iter& List::_Iter::operator++() throw(ListException);
// Forces the iterator to point to the successor element in the list
// An iterator pointing past-the-end of a list (e.g. iterator end() ),
// is not incrementable. Instead an object of type ListException is thrown
List::_Iter& List::_Iter::operator--() throw(ListException)
// Forces the iterator to point to the forerunner element in the list
// An iterator, pointing to the first element of a list (e.g. iterator a.begin() ),
// is not decrementable. Instead an object of type ListException is thrown
List::_Iter List::_Iter::operator++(int); // voluntarily
// Semantic of iter++: { iterator tmp = iter; ++iter; return tmp; }
List::_Iter List::_Iter::operator--(int); // voluntarily
// Semantic of iter--: { iterator tmp = iter; --iter; return tmp; }
bool List::_Iter::operator==( const List::_Iter& iter ) const;
// iter1 == iter2 returns true if both iterators point the the same element.
bool List::_Iter::operator!=( const _Iter& iter ) const;
// a!=b is equivalent to !(a==b)
List::_Iter List::begin();
// begin() returns an iterator referring to the first element in the container.
// If the container is empty, then begin() == end();
List::_Iter List::end();
// end() returns an iterator which is the past-the-end value for the container.
// past-the-end iterators are not dereferenceable
// If the container is empty, then begin() == end();
PG2-WS08-Teil5-Projekt FC.doc
Seite 4 von 5
Anlage 2
template<typename T> class List {
public:
class _Iter; //Vorwärtsdeklaration
private:
class ListElem {
/* omitted declarations */
}; // END class ListElem
ListElem* psentinel;
/* omitted declarations */
public:
typedef
typedef
typedef
typedef
typedef
typedef
unsigned long size_type;
T value_type;
T* pointer;
T& reference;
long difference_type;
_Iter iterator;
size_type size() const;
T& front();
/* omitted declarations */
class _Iter {
public:
/* omitted declarations */
private:
/* omitted declarations */
}; // END class _Iter
_Iter begin();
/* omitted declarations */
}; // END class List
PG2-WS08-Teil5-Projekt FC.doc
Seite 5 von 5