Array exception
A. First Edition
This is second edition of my simple assignment which requires you to write both template and exception handling.
What should I say about this?
E.Further improvement
1. I should write one more user-defined class object for testing.
//file Array.h
/////////////////////////////////// // Date: August 10, 2003 // Author: C. Taillefer // File: Array.h /////////////////////////////////// // Array Header File with patial // implementation. /////////////////////////////////// #ifndef ARRAY_H #define ARRAY_H #include <iostream> using namespace std; #include "exception.h" template < class T > class Array { friend ostream &operator<<( ostream & output, const Array<T>& a ) { for ( int i = 0; i < a.size; i++ ) { output << ' ' << a.ptr[ i ]; } return output ; } public: Array( int = 10 ); // default constructor Array( const Array & ); // copy constructor ~Array(); // destructor int getSize() const; // return size T& operator[]( int index ) ; bool operator==( const Array& ) const ; const Array& operator() ( int first, int last ) ; private: int size; // size of the array T* ptr; // pointer to first element of array }; ////////////////////////////////////////////////////////////////// // Default constructor for class Array (default size 10) template < class T > Array< T >::Array( int arraySize ) { if (arraySize <= 0 ) { throw Error( "Invalid Size" ) ; } else { size = arraySize ; ptr = new T[ size ]; // create space for array if ( ptr == 0 ) { throw Error( "No Memory Allocation" ) ; } for ( int i = 0; i < size; i++ ) ptr[ i ] = 0; // initialize array } } //////////////////////////////////////////////////////////////// // Copy constructor for class Array // must receive a reference to prevent infinite recursion template < class T > Array< T >::Array( const Array &init ) : size( init.size ) { ptr = new T[ size ]; // create space for array if ( ptr == 0 ) { throw Error( "No Memory Allocation" ) ; } for ( int i = 0; i < size; i++ ) ptr[ i ] = init.ptr[ i ]; // copy init into object } //////////////////////////////////////////////////////////////// // Destructor for class Array template < class T > Array< T >::~Array() { delete [] ptr; // reclaim space for array } //////////////////////////////////////////////////////////////// // Get the size of the array template < class T > int Array< T >::getSize() const { return size; } //////////////////////////////////////////////////////////////// // Overloaded subscript operator for class Array template < class T > T& Array< T >::operator[]( int index ) { if (index >= size ) { throw Error( "Index Out of Bounds" ) ; } return ptr[ index ] ; } //if user pass a "class T", say "Student" which is a user-defined class, //then user must define operator overloading function: // bool Student::operator==(Student& S); template< class T > bool Array<T>::operator ==(const Array<T>& other) const { if (this==&other)//test if this object { return true; } else { if (size==other.size)//size must be same { for (int i=0; i<size; i++) { //I guess for a certain class "T", user usually only defines "==" //instead of "!=" if (!(ptr[i]==other.ptr[i]))//should user define this by himself? { return false; } } return true;//this means all element is equal } } return false; } //return object itself with chopped off array template< class T > const Array<T>& Array<T>::operator()(int first, int last) { if (first<0||last<0) { throw Error("Negative subscript not allowed!"); } if (last<first) { throw Error("Last cannot be smaller than first!"); } if (first>=size||last>=size) { throw Error("Index Out of Bounds"); } if (first==0&&last==size-1)//this is a shortcut which returns original itself { return *this; } //use safe mode to backup old ptr and size, in case exception, try restore them T* oldPtr = ptr; int oldSize = size; size = last - first + 1; ptr = new T [size]; if (ptr==NULL) { //before throw, restore old data first ptr= oldPtr; size = oldSize; throw Error("No Memory Allocation"); } for (int i=0; i<size; i++) { ptr[i] = oldPtr[first+i]; } delete [] oldPtr;//delete old ptr return *this; } #endif
//file Exception.h
/////////////////////////////////// // Date: August 10, 2003 // Author: C. Taillefer // File: exception.h /////////////////////////////////// // Exception Object Header File // with implementation. /////////////////////////////////// #ifndef EXCEPTION_H #define EXCEPTION_H #include <cstring> class Error { public: Error( char* msg = "" ) { message = new char[ strlen(msg)+1 ] ; strcpy( message, msg ) ; } Error( const Error& err ) { message = new char[ strlen(err.message)+1 ] ; strcpy( message, err.message ) ; } ~Error() { delete [] message ; } const char* what() { return message ; } private: char* message ; } ; #endif
//file Driver.cpp
/////////////////////////////////// // Date: August 13, 2003 // Author: Qingzhe Huang // File: Driver.cpp /////////////////////////////////// // Driver .cpp file and major feature is: // 1. I don't like copy&paste same code, so I made a template function generalTest() // which takes the array object with parameter and also its type. Therefore, I can // test all type of template array with this templated function. // 2. Originally I also want to test array with object, say a user-defined class "Student", // but it takes more time. (this class must define "operator==" as my array need this in // its member function, so does "assign operator=". // /////////////////////////////////// #include <iostream> #include "Array.h" #include "Exception.h" using namespace std; //this template function can test all data type provided //user pass a data array with same data type of the array class template<class T> void generalTest(Array<T>& A, T* dataArray); int main() { char* strArray[6]={"str1","str2","str3","str4","str5","str6"}; int integerArray[12] = {1,2,3,4,5,6,7,8,9,10,11,12}; Array<int> intArray(12); Array<char*> charArray(6); //test int type with int data array generalTest<int>(intArray, integerArray); generalTest<char*>(charArray, strArray); return 0; } //this saves those copy&paste garbage code as you don't need to write //same code to test every data type. template<class T> void generalTest(Array<T>& A, T* dataArray) { cout<<"test constructor by assign negative size\n"; try { Array<T> temp(-1); } catch(Error E) { cout<<E.what()<<endl; } cout<<"test friend function and operator[]"<<endl; for (int i=0; i<A.getSize(); i++) { A[i] = dataArray[i]; } cout<<A<<endl; cout<<"Here goes the try block, see if ""out of bounds"" error can be caught" <<" by access one more than size\n"; try { cout<<"The size of object is "<<A.getSize()<<endl; cout<<"try to access one more than size"<<endl; cout<<A[A.getSize()+1]; } catch(Error E) { cout<<E.what()<<endl; } cout<<"now test operator== by compare object itself\n"; cout<<"A==A should be: "<<(A==A?"true":"false")<<endl; cout<<"now test operator == by compare object with different size\n"; Array<T> B(A.getSize()-1); for (i=0; i<B.getSize(); i++) { B[i] = dataArray[i]; } cout<<"A, B with different size,so (A==B) should be: "<<(A==B?"true":"false")<<endl; cout<<"now test copy constructor\n"; Array<T> C(A); cout<<"C is created by initialized by A, so C==A should be: " <<(C==A?"true":"false")<<endl; cout<<"now try to catch No Memory Allocated by allocating too much memory\n"; try { Array<T> D(999999999); } catch(Error E) { cout<<E.what()<<endl; } cout<<"Now try substring function by passing nagative subscript\n"; try { cout<<A(-1, A.getSize() -2); } catch(Error E) { cout<<E.what()<<endl; } cout<<"try to test last is smaller than first\n"; try { cout<<A(A.getSize()-4, A.getSize()-5); } catch(Error E) { cout<<E.what()<<endl; } cout<<"try to get correct substring\n"; try { cout<<"original array is like this\n"<<A<<endl; cout<<"now substring is like this\n"<<A(A.getSize()-5, A.getSize()-3)<<endl; } catch(Error E) { cout<<E.what()<<endl; } }
Running result of program: