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: