C++/Class/template class

Материал из C\C++ эксперт
Перейти к: навигация, поиск

A generic safe-array class that prevents array boundary errors.

  
#include <iostream>
#include <new>
#include <cstdlib>
using namespace std;
template <class T, int len> class dyn_safe_array {
  T *aptr;  
  int length;
public:
  dyn_safe_array();
  // copy constructor.
  dyn_safe_array(const dyn_safe_array &obj);
  // Release the allocated memory when a dyn_safe_array object goes out of scope.
  ~dyn_safe_array() {
     delete [] aptr;
  }
  // Overload assignment.
  dyn_safe_array &operator=(const dyn_safe_array<T,len> &rh_op);
  // Use the subscripting operator to access elements in the safe array.
  T &operator[](int i);
  
  // Return the size of the array.
  int getlen() { return length; }
};
// constructor.
template <class T, int len>
dyn_safe_array<T, len>::dyn_safe_array() {
  try {
    aptr = new T[len];
  } catch(bad_alloc ba) {
    cout << "Can"t allocate array.\n";
    // Take appropriate action here. This is just
    // a placeholder response.
    exit(1);
  }
  // Initialize the array elements to their default value.
  for(int i=0; i < len; ++i) aptr[i] = T();
  length = len;
}
// copy constructor.
template <class T, int len>
dyn_safe_array<T, len>::dyn_safe_array(const dyn_safe_array &obj) {
  cout << "Using dyn_safe_array"s copy constructor to make a copy.\n";
  try {
    aptr = new T[obj.length];
  } catch(bad_alloc ba) {
    cout << "Can"t allocate array.\n";
    exit(1);
  }
  length = obj.length;
  // Copy contents of the array.
  for(int i=0; i < length; ++i)
    aptr[i] = obj.aptr[i];
}
// Overload assignment so that a copy of the array is made.
// The copy is stored in an allocated memory that is separate
// from that used by the right-hand operand.
template<class T, int len> dyn_safe_array<T, len> &
dyn_safe_array<T, len>::operator=(const dyn_safe_array<T, len> &rh_op) {
 // If necessary, release the memory currently used by the object.
 if(aptr && (length != rh_op.length)) {
   // Delete the previously allocated memory.
   delete aptr;
   try {
     // Allocate an array of the same size as the one used by rh_op.
     aptr = new T[rh_op.length];
   } catch(bad_alloc ba) {
     // Take appropriate action here. This is just a placeholder response.
     cout << "Can"t allocate array.\n";
     exit(1);
   }
 }
 length = rh_op.length;
 // Copy contents of the array.
 for(int i=0; i < length; ++i)
   aptr[i] = rh_op.aptr[i];
   return *this;
}
template <class T, int len> T &dyn_safe_array<T, len>::operator[](int i)
{
  if(i < 0 || i > length) {
    cout << "\nIndex value of " << i << " is out-of-bounds.\n";
    exit(1);
  }
  return aptr[i];
}
template <class T, int len>
dyn_safe_array<T, len> f(dyn_safe_array<T, len> x) {
  cout << "f() is returning a copy of x.\n";
  return x;
}
class myclass {
public:
  int x;
  myclass(int i) { x = i; };
  myclass() { x = -1; }
};
int main()
{
  // Use the integer array.
  dyn_safe_array<int, 5> i_ar;
  for(int i=0; i < i_ar.getlen(); ++i) i_ar[i] = i;
  cout << "Contents of i_ar: ";
  for(int i=0; i < i_ar.getlen(); ++i) cout << i_ar[i] << " ";
  cout << "\n\n";
  dyn_safe_array<int, 5> i_ar2 = i_ar;
  for(int i=0; i < i_ar2.getlen(); ++i) cout << i_ar2[i] << " ";
  dyn_safe_array<int, 5> i_ar3;
  for(int i=0; i < i_ar3.getlen(); ++i) cout << i_ar3[i] << " ";
  cout <<"\n\n";
  i_ar3 = f(i_ar);
  for(int i=0; i < i_ar3.getlen(); ++i)  cout << i_ar3[i] << " ";
  cout << "\n\n";
  dyn_safe_array<myclass, 3> mc_ar;
  cout << "Original contents of mc_ar: ";
  for(int i=0; i < mc_ar.getlen(); ++i) cout << mc_ar[i].x << " ";
  cout << endl;
  mc_ar[0].x = 9;
  mc_ar[1].x = 8;
  mc_ar[2].x = 7;
  for(int i=0; i < mc_ar.getlen(); ++i) cout << mc_ar[i].x << " ";
  cout << "\n\n";
  cout << "   mc_ar2 = f(mc_ar);\n\n";
  dyn_safe_array<myclass, 3> mc_ar2;
  mc_ar2 = f(mc_ar);
  cout << "Contents of mc_ar2 after receiving f(mc_ar): ";
  for(int i=0; i < mc_ar2.getlen(); ++i) cout << mc_ar2[i].x << " ";
  cout << endl;
  return 0;
}


An Example with Two Generic Data Types

   
#include <iostream>
using namespace std;
   
template <class Type1, class Type2> class myclass
{
  Type1 i;
  Type2 j;
public:
  myclass(Type1 a, Type2 b) { i = a; j = b; }
  void show() { cout << i << " " << j << "\n"; }
};
   
int main()
{
  myclass<int, double> ob1(10, 0.23);
  myclass<char, char *> ob2("X", "Templates add power.");
   
  ob1.show(); 
  ob2.show(); 
   
  return 0;
}


Applying Template Classes: A Generic Array Class

   
#include <iostream>
#include <cstdlib>
using namespace std;
   
const int SIZE = 10;
   
template <class T> class MyClass {
  T a[SIZE];
public:
  MyClass() {
    register int i;
    for(i=0; i<SIZE; i++) a[i] = i;
  }
  T &operator[](int i);
};
   
template <class T> T &MyClass<T>::operator[](int i)
{
  if(i<0 || i> SIZE-1) {
    cout << "\nIndex value of ";
    cout << i << " is out-of-bounds.\n";
    exit(1);
  }
  return a[i];
}
   
int main()
{
  MyClass<int> intob; // integer array
  MyClass<double> doubleob; // double array
   
  for(int i=0; i<SIZE; i++) intob[i] = i;
  for(int i=0; i<SIZE; i++) cout << intob[i] << endl;
   
  for(int i=0; i<SIZE; i++) doubleob[i] = (double) i/3;
  for(int i=0; i<SIZE; i++) cout << doubleob[i] << endl;
   
  return 0;
}


Demonstrate a very simple safe pointer class.

  
#include <iostream>
#include <string>
using namespace std;
// The exception type thrown by the safe pointer.
class bad_ptr {
public:
  string msg;
  bad_ptr(string str) { msg = str; }
};
// A class used to demonstrate the safe pointer.
class myclass {
public:
  int alpha;
  int beta;
  myclass(int p, int q) { alpha = p; beta = q; }
};
template <class T> class safe_ptr {
  T *ptr;
public:
  safe_ptr() { ptr = 0; }
  T *operator->() {
    if(!ptr != 0) throw bad_ptr("Attempt to use -> on null pointer.");
    else return ptr;
  }
  T &operator*() {
    if(!ptr) throw bad_ptr("Attempt to dereference null pointer.");
    else return *ptr;
  }
  operator T *() { return ptr; }
  T *operator=(T *val) { ptr = val; return ptr; }
};
int main()
{
  safe_ptr<int> intptr;
  try {
    *intptr = 23;
    cout << "The value pointed to by intptr is: " << *intptr << endl;
  } catch(bad_ptr bp) {
    cout << bp.msg << endl;
  }
  intptr = new int;
  try {
    *intptr = 23;
    cout << "The value pointed to by intpr is: " << *intptr << "\n\n";
  } catch(bad_ptr bp) {
    cout << bp.msg << endl;
  }
  safe_ptr<myclass> mcptr;
  try {
    mcptr = new myclass(100, 200);
    cout << "The values of alpha and beta for mcptr are: "
         << mcptr->alpha << " and " << mcptr->beta << endl;
    mcptr->alpha = 27;
    cout << "New value for mcptr->alpha: " << mcptr->alpha << endl;
    cout << "Same as (*mcptr).alpha: " << (*mcptr).alpha << endl;
    mcptr->beta = 99;
    cout << "New value for mcptr->beta: " << mcptr->beta << "\n\n";
  } catch(bad_ptr bp) {
    cout << bp.msg << endl;
  }
  safe_ptr<myclass> mcptr2;
  try {
    mcptr2->alpha = 88;
  } catch(bad_ptr bp) {
    cout << bp.msg << endl;
  }
  delete intptr;
  delete mcptr;
  return 0;
}


Explicit Class Specializations for generic template class

   
#include <iostream>
using namespace std;
   
template <class T> class myclass {
  T x;
public:
  myclass(T a) {
    cout << "Inside generic myclass\n";
    x = a;
  }
  T getx() { return x; }
};
   
template <> class myclass<int> {
  int x;
public:
  myclass(int a) {
    cout << "Inside myclass<int> specialization\n";
    x = a * a;
  }
  int getx() { return x; }
};
   
int main()
{
  myclass<double> d(10.1);
  cout << "double: " << d.getx() << "\n\n";
   
  myclass<int> i(5);
  cout << "int: " << i.getx() << "\n";
   
  return 0;
}


Generic Classes: demonstrates a generic stack.

   
#include <iostream>
using namespace std;
   
const int SIZE = 10;
   
template <class StackType> class stack {
  StackType stck[SIZE]; 
  int tos; 
   
public:
  stack() { tos = 0; } 
  void push(StackType ob); 
  StackType pop(); 
};
template <class StackType> void stack<StackType>::push(StackType ob)
{
  if(tos==SIZE) {
    cout << "Stack is full.\n";
    return;
  }
  stck[tos] = ob;
  tos++;
}
template <class StackType> StackType stack<StackType>::pop()
{
  if(tos==0) {
    cout << "Stack is empty.\n";
    return 0; // return null on empty stack
  }
  tos--;
  return stck[tos];
}
   
int main()
{
  stack<char> s1, s2;
   
  s1.push("a");
  s2.push("x");
  s1.push("b");
  s2.push("y");
  s1.push("c");
  s2.push("z");
   
  for(int i=0; i<3; i++) cout << "Pop s1: " << s1.pop() << "\n";
  for(int i=0; i<3; i++) cout << "Pop s2: " << s2.pop() << "\n";
   
  stack<double> ds1, ds2;
   
  ds1.push(1.1);
  ds2.push(2.2);
  ds1.push(3.3);
  ds2.push(4.4);
  ds1.push(5.5);
  ds2.push(6.6);
   
  for(int i=0; i<3; i++) cout << "Pop ds1: " << ds1.pop() << "\n";
  for(int i=0; i<3; i++) cout << "Pop ds2: " << ds2.pop() << "\n";
   
  return 0;
}


generic stack template class

  
#include <iostream>
using namespace std;
const int SIZE = 100;
template <class SType> class stack {
   SType stck[SIZE];
   int tos;
 public:
   stack(void);
   ~stack(void);
   void push(SType i);
   SType pop(void);
 };
template <class SType> stack<SType>::stack()
{
   tos = 0;
   cout << "Stack Initialized." << endl;
}
template <class SType> stack<SType>::~stack()
{
   cout << "Stack Destroyed." << endl;
}
template <class SType> void stack<SType>::push(SType i)
{
   if(tos==SIZE)
    {
      cout << "Stack is full." << endl;
      return;
    }
   stck[tos++] = i;
}
template <class SType> SType stack<SType>::pop(void)
{
   if(tos==0)
    {
      cout << "Stack underflow." << endl;
      return 0;
    }
   return stck[--tos];
}
int main(void)
{
   stack<int> a;
   stack<double> b;
   stack<char> c;
   int i;
   a.push(1);
   a.push(2);
   b.push(99.3);
   b.push(-12.23);
   cout << a.pop() << " ";
   cout << a.pop() << " ";
   cout << b.pop() << " ";
   cout << b.pop() << endl;
   for(i=0; i<10; i++)
      c.push((char) "A" + i);
   for(i=0; i<10; i++)
      cout << c.pop();
   cout << endl;
}


Get storage off stack for array

  
#include <iostream>
using namespace std;
template <class T, int n>
class assign_array {
public:
   T  a[n];
};
int main()
{
   assign_array<double, 50>  x, y;
   for (int i = 0; i < 50; ++i)
      x.a[i] = i;
   for (int i = 0; i < 50; ++i)
      y.a[i] = i * 2;
   for (int i = 0; i < 50; ++i)
      cout << x.a[i] << "\t";
   for (int i = 0; i < 50; ++i)
      cout << y.a[i] << "\t";
   x = y;                     //should work efficiently
   for (int i = 0; i < 50; ++i)
      cout << x.a[i] << "\t";
}


Passing by reference and using virtual functions in exceptions.

  
#include <iostream>
using namespace std;
const int DefaultSize = 10;
class Array
{
public:
    Array(int itsSize = DefaultSize);
    Array(const Array &rhs);
    ~Array() { delete [] pType;}
    Array& operator=(const Array&);
    int& operator[](int offSet);
    const int& operator[](int offSet) const;
    int GetitsSize() const { return itsSize; }
    friend ostream& operator<< (ostream&, const Array&);
    class xBoundary {};
    class xSize
    {
    public:
       xSize(int size):itsSize(size) {}
       ~xSize(){}
       virtual int GetSize() { return itsSize; }
       virtual void PrintError() 
       { 
           cout << "Size error. Received: ";
           cout << itsSize << endl; 
       }
    protected:
       int itsSize;
    };
    class xTooBig : public xSize
    {
    public:
       xTooBig(int size):xSize(size){}
       virtual void PrintError() 
       { 
           cout << "Too big! Received: ";
           cout << xSize::itsSize << endl; 
       }
    };
    class xTooSmall : public xSize
    {
    public:
       xTooSmall(int size):xSize(size){}
       virtual void PrintError() 
       { 
           cout << "Too small! Received: ";
           cout << xSize::itsSize << endl; 
       }
    };
    class xZero  : public xTooSmall
    {
    public:
       xZero(int size):xTooSmall(size){}
       virtual void PrintError() 
       { 
           cout << "Zero!!. Received: " ;
           cout << xSize::itsSize << endl; 
       }
    };
    class xNegative : public xSize
    {
    public:
       xNegative(int size):xSize(size){}
       virtual void PrintError() 
       { 
           cout << "Negative! Received: ";
           cout << xSize::itsSize << endl; 
       }
    };
 private:
    int *pType;
    int  itsSize;
 };
 Array::Array(int size):
 itsSize(size)
 {
    if (size == 0)
       throw xZero(size);
    if (size > 30000)
       throw xTooBig(size);
    if (size <1)
       throw xNegative(size);
    if (size < 10)
        throw xTooSmall(size);
     pType = new int[size];
     for (int i = 0; i<size; i++)
       pType[i] = 0;
  }
  int& Array::operator[] (int offSet)
  {
      int size = GetitsSize();
      if (offSet >= 0 && offSet < GetitsSize())
        return pType[offSet];
      throw xBoundary();
      return pType[0];
  }
  const int& Array::operator[] (int offSet) const
  {
      int size = GetitsSize();
      if (offSet >= 0 && offSet < GetitsSize())
        return pType[offSet];
      throw xBoundary();
      return pType[0];
  }
   int main()
   {
      try
      {
         Array intArray(9);
         for (int j = 0; j< 100; j++)
         {
            intArray[j] = j;
            cout << "intArray[" << j << "] okay...\n";
         }
      }
      catch (Array::xBoundary)
     {
        cout << "Unable to process your input!\n";
     }
     catch (Array::xSize& theException)
     {
        theException.PrintError();
     }
     catch (...)
     {
        cout << "Something went wrong!\n";
     }
     cout << "Done.\n";
    return 0;
}


sequence template

  
#include <iostream>
using namespace std;
template <class T, int N>
class sequence {
    T memblock [N];
  public:
    void setmember (int x, T value);
    T getmember (int x);
};
template <class T, int N>
void sequence<T,N>::setmember (int x, T value) {
  memblock[x]=value;
}
template <class T, int N>
T sequence<T,N>::getmember (int x) {
  return memblock[x];
}
int main () {
  sequence <int,5> myints;
  sequence <double,5> myfloats;
  myints.setmember (0,100);
  myfloats.setmember (3,3.1416);
  cout << myints.getmember(0) << "\n";
  cout << myfloats.getmember(3) << "\n";
  return 0;
}


template class with generic parameter

  
#include <iostream>
using namespace std;
template<class T> class Distance {
  public:
    Distance(T distance); 
    void show_distance(void) { 
       cout << "The distance is " << distance << " miles\n"; 
    };
  private:
    T distance;
};
template<class T>
Distance<T>::Distance(T distance) { Distance::distance = distance; };
int main(void)
{
    Distance<int> short_distance(100);
    Distance<long> long_distance(2000000L);
    short_distance.show_distance();
    long_distance.show_distance();
}


template class with two generic parameters

  
#include <iostream>
using namespace std;
template <class T1, class T2> class two_gen {
   T1 i;
   T2 j;
 public:
   two_gen(T1 a, T2 b)
      { i=a; j=b;}
   void show(void)
      { cout << i << " " << j << endl; }
};
int main(void)
{
   two_gen<int, double> obj1(10, 0.23);
   two_gen<char, char *> obj2("X", "This is a test.");
   obj1.show();
   obj2.show();
}


template class with type parameter

  
#include <iostream>
#include <stdlib.h>
using namespace std;
const int SIZE = 10;
template <class T> class MyClass {
   T a[SIZE];
 public:
   MyClass(void)
    {
      int i;
      for(i=0; i<SIZE; i++)
         a[i] = i;
    }
   T &operator[](int i);
};
template <class T> T &MyClass<T>::operator[](int i)
{
   if(i<0 || i> SIZE-1)
    {
      cout << endl << "Index value of ";
      cout << i << " is out of bounds." << endl;
    }
   return a[i];
}
int main(void)
{
   MyClass<int> int_array;
   MyClass<double> double_array;
   int i;
   cout << "Integer array: ";
   for(i=0; i<SIZE; i++)
      int_array[i] = i;
   for(i=0; i<SIZE; i++)
      cout << int_array[i] << " ";
   cout << endl;
   cout << "Double array: ";
   cout.precision(2);
   for(i=0; i<SIZE; i++)
      double_array[i] = (double)i/3;
   for(i=0; i<SIZE; i++)
      cout << double_array[i] << " ";
   cout << endl;
   int_array[12] = 100;                 // Calls overloaded array operator
}


template extending

  
template <typename T>
class SimpleTemplate
{
 public:
  SimpleTemplate(T &inObject);
  const T& get();
  void set(T& inObject);
 protected:
  T& mObject;
};
template <typename T>
SimpleTemplate<T>::SimpleTemplate(T &inObject) : mObject(inObject)
{
}
template <typename T>
const T& SimpleTemplate<T>::get()
{
  return mObject;
}
template <typename T>
void SimpleTemplate<T>::set(T& inObject)
{
  mObject = inObject;
}
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char** argv)
{
  int i = 7;
  SimpleTemplate<int> intWrapper(i);
  i = 2;
  cout << "wrapper value is " << intWrapper.get() << endl;
  string str = "test";
  SimpleTemplate<string> stringWrapper(str);
  str += "!";
  cout << "wrapper value is " << stringWrapper.get() << endl;
}


Template Version of Generic binary sorted Tree.

  
#include  <iostream>
#include  <string.h>
using namespace std;
//A generic binary sorted tree.
template <class T>  class gen_tree;     //forward decl
template <class T>
class bnode {
private:
   friend class gen_tree<T>;
   bnode<T>*  left;
   bnode<T>*  right;
   T          data;
   int        count;
   bnode(T d, bnode<T>* l, bnode<T>* r) :
         data(d), left(l), right(r), count(1) { }
   void  print() const
      { cout << data << " : " << count << "\t"; }
};
template <class T>
class gen_tree {
public:
   gen_tree() { root = 0; }
   void  insert(T d);
   T  find(T d) const { return (find(root, d)); }
   void  print() const { print(root); }
private:
   bnode<T>*  root;
   T  find(bnode<T>* r, T d) const;
   void  print(bnode<T>* r) const;
};
template <class T>
void gen_tree<T>::insert(T d)
{
   bnode<T>*  temp = root;
   bnode<T>*  old;
   if (root == 0) {
      root = new bnode<T>(d, 0, 0);
      return;
   }
   while (temp != 0) {
      old = temp;
      if (comp(temp -> data, d) == 0) {
         (temp -> count)++;
         return;
      }
      if (comp(temp -> data, d) > 0)
         temp = temp -> left;
      else
         temp = temp -> right;
   }
   if (comp(old -> data, d) > 0)
      old -> left = new bnode<T>(d, 0, 0);
   else
      old -> right = new bnode<T>(d, 0, 0);
}
template <class T>
T gen_tree<T>::find(bnode<T>* r, T d) const
{
   if (r == 0)
      return 0;
   else if (comp(r -> data, d) ==  0)
      return (r -> data);
   else if (comp(r -> data, d) > 0)
      return (find( r -> left, d));
   else
      return (find( r -> right, d));
}
template <class T>
void gen_tree<T>::print(bnode<T> *r) const
{
   if (r != 0) {
      print( r -> left);
      r -> bnode<T>::print();
      print ( r -> right);
   }
}
template <class T>      //general case
int comp(T i, T j)
{
   if (i == j)          //assumes ==  < defined for T
      return 0;
   else
      return ( (i < j) ? -1 : 1 );
}
//specialization for const char*
int comp(const char* i, const char* j){
   return (strcmp(i, j));
}
int main()
{
   char             dat[256];
   gen_tree<char*>  t;
   char*            p;
   while (cin>>dat){
      p = new char[strlen(dat) + 1];
      strcpy(p, dat);
      t.insert(p);
   }
   t.print();
   cout << "EOF" << endl << endl;
   gen_tree<int>  i_tree;
   for (int i = 15; i > -5; --i)
      i_tree.insert(i);
   i_tree.print();
}


Using Default Arguments with Template Classes

   
#include <iostream>
#include <cstdlib>
using namespace std;
   
template <class T=int, int size=10> class MyClass {
  T a[size]; // size of array is passed in size
public:
  MyClass() {
    register int i;
    for(i=0; i<size; i++) a[i] = i;
  }
  T &operator[](int i);
};
   
template <class T, int size>
T &MyClass<T, size>::operator[](int i)
{
  if(i<0 || i> size-1) {
    cout << "\nIndex value of ";
    cout << i << " is out-of-bounds.\n";
    exit(1);
  }
  return a[i];
}
   
int main()
{
  MyClass<int, 100> intarray;  
  MyClass<double> doublearray; 
  MyClass<> defarray;          
   
  cout << "int array: ";
  for(int i=0; i<100; i++) intarray[i] = i;
  for(int i=0; i<100; i++) cout << intarray[i] << endl;
   
  cout << "double array: ";
  for(int i=0; i<10; i++) doublearray[i] = (double) i/3;
  for(int i=0; i<10; i++) cout << doublearray[i] << endl;
   
  cout << "defarray array: ";
  for(int i=0; i<10; i++) defarray[i] = i;
  for(int i=0; i<10; i++) cout << defarray[i] << endl;
   
  return 0;
}


Using exceptions with templates.

  
#include <iostream>
using namespace std;
const int DefaultSize = 10;
class xBoundary {};
template <class T>
class Array
{
public:
    Array(int itsSize = DefaultSize);
    Array(const Array &rhs);
    ~Array() { delete [] pType;}
    Array& operator=(const Array<T>&);
    T& operator[](int offSet);
    const T& operator[](int offSet) const;
    int GetitsSize() const { return itsSize; }
    friend ostream& operator<< (ostream&, const Array<T>&);
    class xSize {};
 private:
    int *pType;
    int  itsSize;
 };
 template <class T>
 Array<T>::Array(int size):
 itsSize(size)
 {
    if (size <10 || size > 30000)
       throw xSize();
    pType = new T[size];
    for (int i = 0; i<size; i++)
      pType[i] = 0;
 }
 template <class T>
 Array<T>& Array<T>::operator=(const Array<T> &rhs)
 {
    if (this == &rhs)
       return *this;
    delete [] pType;
    itsSize = rhs.GetitsSize();
    pType = new T[itsSize];
    for (int i = 0; i<itsSize; i++)
       pType[i] = rhs[i];
 }
 template <class T>
 Array<T>::Array(const Array<T> &rhs)
 {
    itsSize = rhs.GetitsSize();
    pType = new T[itsSize];
    for (int i = 0; i<itsSize; i++)
       pType[i] = rhs[i];
 }
 template <class T>
 T& Array<T>::operator[](int offSet)
 {
    int size = GetitsSize();
    if (offSet >= 0 && offSet < GetitsSize())
       return pType[offSet];
    throw xBoundary();
    return pType[0];
 }
 template <class T>
 const T& Array<T>::operator[](int offSet) const
 {
    int mysize = GetitsSize();
    if (offSet >= 0 && offSet < GetitsSize())
       return pType[offSet];
    throw xBoundary();
 }
 template <class T>
 ostream& operator<< (ostream& output, const Array<T>& theArray)
 {
    for (int i = 0; i<theArray.GetitsSize(); i++)
       output << "[" << i << "] " << theArray[i] << endl;
    return output;
 }
int main(){
    try
    {
       Array<int> intArray(9);
       for (int j = 0; j< 100; j++)
        {
           intArray[j] = j;
           cout << "intArray[" << j << "] okay..." << endl;
        }
     }
     catch (xBoundary)
     {
        cout << "Unable to process your input!\n";
     }
     catch (Array<int>::xSize)
     {
        cout << "Bad Size!\n";
     }
     cout << "Done.\n";
     return 0;
}


Using Non-Type Arguments with Generic Classes

   
#include <iostream>
#include <cstdlib>
using namespace std;
   
template <class T, int size> class MyClass {
  T a[size]; // length of array is passed in size
public:
  MyClass() {
    register int i;
    for(i=0; i<size; i++) a[i] = i;
  }
  T &operator[](int i);
};
   
template <class T, int size>
T &MyClass<T, size>::operator[](int i)
{
  if(i<0 || i> size-1) {
    cout << i << " is out-of-bounds.\n";
    exit(1);
  }
  return a[i];
}
   
int main()
{
  MyClass<int, 10> intob;       
  MyClass<double, 15> doubleob; 
   
  for(int i=0; i<10; i++) 
     intob[i] = i;
  for(int i=0; i<10; i++) 
     cout << intob[i] << endl;
   
  for(int i=0; i<15; i++) 
     doubleob[i] = (double) i/3;
  for(int i=0; i<15; i++) 
     cout << doubleob[i] << "  ";
   
  return 0;
}