// CSC 601 - Fall 2002 - Kirby // ------------------------------------------------------------------------ // A slightly edited transcript of the code we wrote in class, Tuesday 8/27. // Commenting is mostly absent, since in class we talked through this. // // Purpose: TO review basic OO constructs in C++. // This is "pedagogical" code, meant to make certain design and C++ points, // and should not be viewed as a polished, optimal product. // (Of course, all we really needed was deque.) // // For convenience, we dumped everything in one source file. // ------------------------------------------------------------------------ // IQueue.h // -------- // An interface as an abstract superclass. // // [ Note the presence of one concrete method (empty()), to hint at another design // possibility: make ALL public methods concrete, having them call private virtual // methods. Reference: Sutter, "Virtuality", C/C++ Users Journal, Sep 2001.] #include #include #include typedef int T ; // just for now class EmptyQueueException : public std::runtime_error { public: EmptyQueueException( const std::string& msg ) : std::runtime_error( msg ) {} } ; struct IQueue { // inspectors virtual int length() const throw() =0 ; virtual const T& front() const throw ( EmptyQueueException ) =0 ; virtual const T& rear() const throw ( EmptyQueueException ) =0 ; bool empty() const throw() { return length()==0 ; } // mutators virtual T& rear() throw ( EmptyQueueException ) =0 ; virtual void push( const T& item ) throw ( std::exception ) =0 ; virtual void pull() throw ( EmptyQueueException ) =0 ; // virtual dtor virtual ~IQueue() {} ; } ; // ArrayQueue.h // ------------ // A concrete class implementing of IQueue with a fixed circular array. // #include "IQueue.h" class ArrayQueue : public IQueue { public: ArrayQueue( int maxLength ) throw ( std::bad_alloc ) ; ~ArrayQueue() throw() ; // inspectors int length() const throw() ; const T& front() const throw ( EmptyQueueException ) ; const T& rear() const throw ( EmptyQueueException ) ; // mutators T& rear() throw ( EmptyQueueException ) ; void push( const T& item ) throw ( std::out_of_range ) ; void pull() throw ( EmptyQueueException ) ; // constants const int MAXLENGTH ; private: T* _ar ; // _ar[ _front..._rear ] (circularly) holds queue contents int _front, _rear, _length ; } ; // Inlining is nice, hence no methods in concrete class. // But what if exception specifications override inlining request? inline ArrayQueue::ArrayQueue( int maxLength ) throw ( std::bad_alloc ) : MAXLENGTH( maxLength ) , _ar( new T[ maxLength ] ) , _front( 0 ) , _rear( maxLength-1 ) , _length( 0 ) { } inline ArrayQueue::~ArrayQueue() throw() { delete [] _ar ; } inline int ArrayQueue::length() const throw() { return _length ; } inline const T& ArrayQueue::front() const throw ( EmptyQueueException ) { if ( empty() ) throw EmptyQueueException( "attempt to inspect front of empty ArrayQueue." ) ; return _ar[ _front ] ; } inline const T& ArrayQueue::rear() const throw ( EmptyQueueException ) { if ( empty() ) throw EmptyQueueException( "attempt to inspect rear of empty ArrayQueue" ) ; return _ar[ _rear ] ; } inline T& ArrayQueue::rear() throw ( EmptyQueueException ) { if ( empty() ) throw EmptyQueueException( "attempt to access rear of empty ArrayQueue" ) ; return _ar[ _rear ] ; } inline void ArrayQueue::push( const T& item ) throw ( std::out_of_range ) { if ( _length == MAXLENGTH ) throw std::out_of_range( "Attempting to push on a full ArrayQueue." ) ; _rear= (_rear + 1 ) % MAXLENGTH ; _ar[ _rear ]= item ; _length++ ; } inline void ArrayQueue::pull() throw ( EmptyQueueException ) { if ( empty() ) throw EmptyQueueException( "attempt to pull from empty ArrayQueue" ) ; _front= ( _front + 1 ) % MAXLENGTH ; _length-- ; } // QueueDemo.cpp // ------------- // #include "ArrayQueue.h" #include #include using namespace std ; int main() { try { ArrayQueue aq( 5 ) ; IQueue& q= aq ; q.push( 101 ) ; q.push( 102 ) ; q.push( 103 ) ; q.push( 104 ) ; assert( q.length() == 4 ) ; assert( q.rear() == 104 ) ; assert( q.front() == 101 ) ; q.rear() *= 2 ; // mutating access to rear assert( q.rear() == 208 ) ; while ( q.length() > 0 ) q.pull() ; cout << "Ok so far. Going to throw..." << endl ; q.pull() ; } catch ( std::exception& e ) { cout << "Caught: " << e.what() << endl ; } cout << "Done." << endl ; return 0 ; }