410 likes | 472 Views
Template Classes and Functions. Andy Wang Object Oriented Programming in C++ COP 3330. Function Templates. A function template can perform the same algorithm for different types without specifying the types in advance
E N D
Template Classes and Functions Andy Wang Object Oriented Programming in C++ COP 3330
Function Templates • A function template can perform the same algorithm for different types without specifying the types in advance • Example: a function that computes the maximum for three different integers int maximum(int a, int b, int c) { int max = a; if (b > max) max = b; if (c > max) max = c; return max; }
Function Templates • However, this function only works for int variables (or types that can be automatically converted to int) • What if we wanted to compare variables with the type double? • Do we have to write a new function? • A function template allows this problem to be solved easily, with only one function
Templated Version of Maximum • http://www.cs.fsu.edu/~myers/deitel5c++/ch06/Fig06_26_27/
maximum.h template<class T> T maximum(T value1, T value2, T value3) { T maximumValue = value1; if (value2 > maximumValue) maximumValue = value 2; if (value3 > maximumvalue) maximumValue = value 3; return maximumValue; }
figure06_27.cpp #include <iostream> #include “maximum.h” using namespace std; int main() { int int1, int2, int3; cout << “Input three integer values: “; cin >> int1 >> int2 >> int3; cout << “The maximum integer value is: “; << maximum(int1, int2, int3);
figure06_27.cpp double double1, double2, double3; cout << “\n\nInput three double values: “; cin >> double1 >> double2 >> double3; cout << “The maximum double value is: “; << maximum(double1, double2, double3); char char1, char2, char3; cout << “\n\nInput three characters: “; cin >> char1 >> char2 >> char3; cout << “The maximum character value is: “ << maximum(char1, char2, char3); return 0; }
Another Example • http://www.cs.fsu.edu/~myers/deitel5c++/ch14/Fig14_01/fig14_01.cpp • This is a function template that prints the contents of the array template<class T> void printArray(const T*array, constint count) { for (int j = 0; j < count; j++) cout << array[j] << “ “; cout << endl; } • This function will work on arrays of any class type when an appropriate insertion operator << has been defined
Another Example int main() { constintaCount = 5; constintbCount = 7; constintcCount = 6; int a[aCount] = {1, 2, 3, 4, 5}; double b[bCount] = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7}; char c[cCount] = “HELLO”; cout << “Array a contains: “ << endl; printArray(a, aCount); cout << “Array b contains: “ << endl; printArray(b, bCount); cout << “Array c contains: “ << endl; printArray(c, cCount); return 0; }
Example: Swap • http://www.cs.fsu.edu/~myers/savitch3c++/Ch16/16-01.cpp
16-01.cpp #include <iostream> using namespace std; template<class T> void swapValues(T &variable1, T &variable2) { T temp; temp = variable1; variable1 = variable2; variable2 = temp; }
16-01.cpp int main() { int integer1 = 1, integer2 = 2; cout << “Original integer values are “ << integer1 << “ “ << integer2 << endl; swapValues(integer1, integer2); cout << “Swapped integer values are “ << integer1 << “ “ << integer2 << endl; char symbol1 = ‘A’, symbol2 = ‘B’; cout<< "Original character values are: " << symbol1 << " " << symbol2 << endl; swapValues(symbol1, symbol2); cout<< "Swapped character values are: " << symbol1 << " " << symbol2 << endl; return 0; }
Making Container Classes Versatile • Here is an example of a class that uses array-based storage to maintain a list of integers • http://www.cs.fsu.edu/~myers/cop3330/examples/templates/simplelist1/
simplelist1.h constint MAX = 10; class SimpleList { public: SimpleList() { current = 0; } bool Insert(int item); intGetElement(unsigned int n); void Print(); intGetSize() { return current; } private: int array[MAX]; int current; };
simplelist1.cpp #include <iostream> #include “simplelist1.h” using namespace std; bool SimpleList::Insert(int item) { if (current < MAX) { array[current++] = item; return true; } else return false; } intSimpleList::GetElement(unsigned int n) { if (n >= MAX) n = MAX – 1; return array[n]; }
simplelist1.cpp void SimpleList::Print() { if (current == 0) cout << “Empty List”; return; for (int j = 0; j < current – 1; j++) cout << array[j] << ‘ ‘; cout << array[current - 1]; }
Suppose… • We want to have a class that can store a list of double values or a list of characters • We could write a similar class for each for each new type • A common C trick is to use a typedefto create a simple user-defined type • For example, we can define mytype to be a synonym for the type int • typedefintmytype; • We can also define mytype as double • typedef double mytype;
By doing so… • We can define a class using mytype • To change an int array to a double array, just change the typedef for mytype, and recompile • http://www.cs.fsu.edu/~myers/cop3330/examples/templates/simplelist2/
simplelist2.h constint MAX = 10; typedefintmytype; class SimpleList { public: SimpleList() { current = 0; } bool Insert(mytype item); mytypeGetElement(unsigned int n); void Print(); intGetSize() { return current; } private: mytypearray[MAX]; intcurrent; };
simplelist2.cpp #include <iostream> #include "simplelist2.h" using namespace std; bool SimpleList::Insert(mytype item) { if (current < MAX) { array[current++] = item; return true; } else return false; } mytypeSimpleList::GetElement(unsigned int n) { if (n >= MAX) n = MAX - 1; return array[n]; }
simplelist2.cpp void SimpleList::Print() { if (current == 0) { cout<< "Empty List"; return; } for (inti= 0; i < current - 1; i++) cout << array[i] << ' '; cout << array[current - 1]; }
Class Templates • With class templates, we can make this class work with different types without altering and recompiling the code • To make a class into a template, prefix the class definition with the syntax template<class T> • T is a type parameter, and it can have any name • When the class is instantiated, we fill in an appropriate type • Use the same prefix on the definitions of the member functions
Class Templates • For member functions, the name of the class will be className<T>::memberName • In the SimpleList example, the type of the array is T, which will be filled in when an object is created • Also, in the main program, we must #include the actual definition file, in addition to the class declaration • The compiler creates a different version of the class for each type that is used • Thus, either the entire class should be written in the header file, OR the .cpp file should be #included #include “simplelist3.cpp”
SimpleListClass Template Example • http://www.cs.fsu.edu/~myers/cop3330/examples/templates/simplelist3/
simplelist3.h constint MAX = 10; template<class T> class SimpleList { public: SimpleList() { current = 0; } bool Insert(Titem); TGetElement(unsigned int n); void Print(); intGetSize() { return current; } private: Tarray[MAX]; intcurrent; };
simplelist3.cpp #include <iostream> #include "simplelist3.h" using namespace std; #ifndef _SIMPLELIST_CPP #define _SIMPLELIST_CPP template<class T> bool SimpleList<T>::Insert(T item) { if (current < MAX) { array[current++] = item; return true; } else return false; }
simplelist3.cpp template<class T> TSimpleList<T>::GetElement(unsigned int n) { if (n >= MAX) n = MAX - 1; return array[n]; } template<class T> void SimpleList<T>::Print() { if (current == 0) { cout<< "Empty List"; return; } for (inti= 0; i < current-1; i++) cout << array[i] << ' '; cout << array[current - 1]; } #endif
main.cpp #include <iostream> #include “simplelist3.cpp” using namespace std; int main() { SimpeList<int> list1; for (int j = 0; j < 8; j++) list1.Insert(i*3); cout << “Element at index 4 = “ << list1.GetElement(4) << endl; cout << “Entire list is:\n”; list1.Print(); cout << “\n\n”;
main.cpp SimpleList<double> list2; for (int j = 0; j < 10; j++) list2.Insert(j * 1.1); cout << “Element at index 6 = “ << list2.GetElement(6) << endl; cout << “Entire list is:\n”; list2.Print(); cout << “\n\n”; return 0; }
Dynamic List Example • http://www.cs.fsu.edu/~myers/cop3330/examples/templates/tlist/
tlist.h #include <iostream> Using namespace std; #ifndef _LIST_H #define _LIST_H template<class T> class List { public: List(int s = 10); ~List(); List(const List<T> &); List &operator=(const List<T> &); void Insert(T item); T GetElement(unsigned int n); void Print(ostream&os);
tlist.h private: T* data; int size, max; void Clone(const List<T> &); void Resize(intnewsize); }; template<class T> List<T>::List(int s) { size = 0; max = s; if (max <= 0) { data = 0; max = 0; } else data = new T[max]; }
tlist.h template<class T> List<T>::~List() { if (data) delete [] data; } template<class T> List<T>::List(const List<T> &L) { Clone(L); } template<class T> List<T> &List<T>::operator=(const List<T> &L) { if (this != &L) { if (data) delete [] data; Clone(L); } return *this; }
tlist.h template<class T> void List<T>::Insert(T item) { if (max == size) Resize(max + 5); data[size] = item; size++; } template<class T> T List<T>::GetElement(unsigned int n) { if (n >= size) n = size – 1; return data[n]; } template<class T> void List<T>::Print(ostream&os) { if (size == 0) os << “List empty”; for (int j = 0; j < size – 1; j++) os << data[j] << “, “; os << data[size - 1]; }
tlist.h template<class T> void List<T>::Resize(intnewsize) { max = newsize; T *temp = new T[max]; for (int j = 0; j < size; j++) temp[j] = data[j]; if (data != 0) delete [] data; data = temp; } template<class T> void List<T>::Clone(const List<T> &L) { max = L.max; size = L.size; date = new T[max]; for (int j = 0; j < size; j++) data[j] = L.data[j]; }
main.cpp #include <iostream> #include “tlist.h” using namespace std; int main() { List<int> tests; int gr; cout << “Enter some grades (negative to quite):\n “; do { cin >> gr; if (gr >= 0) tests.Insert(gr); } while (gr >= 0); cout << “The 7th element is: “ << test.GetElement(7) << endl; cout << “The 2nd element is: “ << test.GetElement(2) << endl;
main.cpp cout << “Here is the list of grades: \n\n”; test.Print(); cout << “\n\nCreating a list of doubles\n”; List<double> stats(0); double num; cout << “Enter some floating point numbers (negative to quit\n”; do { cin >> num; if (num >= 0) stats.Insert(num); } while (num >= 0);
main.cpp cout << "The 6th element is: " << stats.GetElement(6) << '\n'; cout<< "The 2nd element is: " << stats.GetElement(2) << '\n'; cout<< "Here is the list of doubles:\n\n"; stats.Print(cout); cout<< "\n\n"; return 0; }
main2.cpp #include <iostream> #include <string> #include “tlist.h” using namespace std; template<class T> void TestList(List<T> theList, string label, int val1, int val2) { T gr; cout << “Enter some “ << label << “ (negative to quite):\n “; do { cin >> gr; if (gr >= 0) theList.Insert(gr); } while (gr >= 0)
main2.cpp cout<< "Element " << val1 << " is: " << theList.GetElement(val1) << '\n'; cout<< "Element " << val2 << " is: " << theList.GetElement(val2) << '\n'; cout<< "Here is the list of " << label << ":\n\n"; theList.Print(cout); } int main() { List<int> tests; List<double> stats(0); TestList(tests, "grades", 7, 2); TestList(stats, "floats", 6, 2); }