C++/Class/template class — различия между версиями
Admin (обсуждение | вклад) м (1 версия: Импорт контента...) |
|
(нет различий)
|
Версия 14:21, 25 мая 2010
Содержание
- 1 A generic safe-array class that prevents array boundary errors.
- 2 An Example with Two Generic Data Types
- 3 Applying Template Classes: A Generic Array Class
- 4 Demonstrate a very simple safe pointer class.
- 5 Explicit Class Specializations for generic template class
- 6 Generic Classes: demonstrates a generic stack.
- 7 generic stack template class
- 8 Get storage off stack for array
- 9 Passing by reference and using virtual functions in exceptions.
- 10 sequence template
- 11 template class with generic parameter
- 12 template class with two generic parameters
- 13 template class with type parameter
- 14 template extending
- 15 Template Version of Generic binary sorted Tree.
- 16 Using Default Arguments with Template Classes
- 17 Using exceptions with templates.
- 18 Using Non-Type Arguments with Generic Classes
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;
}