C++/Class/template class — различия между версиями
Admin (обсуждение | вклад) м (1 версия: Импорт контента...) |
|
(нет различий)
|
Текущая версия на 13:25, 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.
<source lang="cpp">
- 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;
}
</source>
An Example with Two Generic Data Types
<source lang="cpp">
- 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;
}
</source>
Applying Template Classes: A Generic Array Class
<source lang="cpp">
- 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;
}
</source>
Demonstrate a very simple safe pointer class.
<source lang="cpp">
- 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;
}
</source>
Explicit Class Specializations for generic template class
<source lang="cpp">
- 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;
}
</source>
Generic Classes: demonstrates a generic stack.
<source lang="cpp">
- 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;
}
</source>
generic stack template class
<source lang="cpp">
- 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;
}
</source>
Get storage off stack for array
<source lang="cpp">
- 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";
}
</source>
Passing by reference and using virtual functions in exceptions.
<source lang="cpp">
- 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;
}
</source>
sequence template
<source lang="cpp">
- 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;
}
</source>
template class with generic parameter
<source lang="cpp">
- 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();
}
</source>
template class with two generic parameters
<source lang="cpp">
- 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();
}
</source>
template class with type parameter
<source lang="cpp">
- 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
}
</source>
template extending
<source lang="cpp"> 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;
}
</source>
Template Version of Generic binary sorted Tree.
<source lang="cpp">
- 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();
}
</source>
Using Default Arguments with Template Classes
<source lang="cpp">
- 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;
}
</source>
Using exceptions with templates.
<source lang="cpp">
- 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;
}
</source>
Using Non-Type Arguments with Generic Classes
<source lang="cpp">
- 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;
}
</source>