What Are Templates?
Templates create a general class and use types as parameters to build specific instances of the parameterized type.
For example, A StringList is a list of strings; a IntegerList is a list of int.
They are both list, which has size() function to return element count. And they all have add() function to append elements, etc.
The only difference is the element type: one is string and the other is int.
With templates, we can create a list of generic type.
To create StringList we replace the generic type with string. To create IntegerList we replace the generic type with int.
The generic type in the list becomes a parameter to the definition of the class.
The action of creating an object from a specific type from a template is called instantiation.
The individual classes are called instances of the template.
You declare a template for a list with the template keyword:
template <class T> // declare the template and the parameter class List // the class being parameterized { public: List(); // full class declaration here };
The keyword template is used at the beginning of every declaration and definition of a template class.
The template's parameters follow the keyword template; they are the items that will change with each instance.
The keyword class is followed by the identifier T.
The keyword class indicates that this parameter is a type.
The identifier T is used throughout the rest of the template definition to refer to the parameterized type.
To declare an int and a string instance of the parameterized list class, you would write the following:
List<int> intList;
List<string> stringList;
The object intList is of the type list of integers; the object stringList is a list of String objects.
#include <iostream> class Data/*w ww. j a v a 2 s . c o m*/ { public: Data(int newVal) :value(newVal) {} ~Data() { std::cout << "Deleting Data object with value: "; std::cout << value << "\n"; } int compare(const Data&); void show() { std::cout << value << "\n"; } private: int value; }; int Data::compare(const Data& otherObject) { if (value < otherObject.value) return -1; if (value > otherObject.value) return 1; else return 0; } class Dog { public: Dog(int newAge) : age(newAge) {} ~Dog() { std::cout << "Deleting "; std::cout << age << "-year-old Dog.\n"; } int compare(const Dog&); void show() { std::cout << "This Dog is "; std::cout << age << " years old\n"; } private: int age; }; // This class compares a different value than Data. int Dog::compare(const Dog& otherDog) { if (age < otherDog.age) return -1; if (age > otherDog.age) return 1; else return 0; } template <class T> class Node { public: Node() {} virtual ~Node() {} virtual Node* insert(T* object) = 0; virtual void show() = 0; private: }; template <class T> class InternalNode : public Node<T> { public: InternalNode(T* object, Node<T>* next); ~InternalNode() { delete next; delete object; } virtual Node<T> * insert(T * object); virtual void show() { object->show(); next->show(); } // delegate! private: T * object; // the object itself Node<T>* next; // points to next node in the linked list }; template <class T> InternalNode<T>::InternalNode(T* newObject, Node<T>* newNext) : object(newObject), next(newNext) { } template <class T> Node<T>* InternalNode<T>::insert(T* newObject) { // is the new object bigger or smaller than me? int result = object->compare(*newObject); switch (result) { // if it is the same as me it goes first case 0: // fall through case 1: // new object comes before me { InternalNode<T>* objectNode = new InternalNode<T>(newObject, this); return objectNode; } case -1: next = next->insert(newObject); return this; } return this; // appease the compiler } // The last node in the list template <class T> class TailNode : public Node<T> { public: TailNode() {} virtual ~TailNode() {} virtual Node<T>* insert(T * object); virtual void show() { } private: }; template <class T> Node<T>* TailNode<T>::insert(T * object) { InternalNode<T>* objectNode = new InternalNode<T>(object, this); return objectNode; } template <class T> class HeadNode : public Node<T> { public: HeadNode(); virtual ~HeadNode() { delete next; } virtual Node<T>* insert(T * object); virtual void show() { next->show(); } private: Node<T> * next; }; template <class T> HeadNode<T>::HeadNode() { next = new TailNode<T>; } template <class T> Node<T> * HeadNode<T>::insert(T* object) { next = next->insert(object); return this; } // I get all the credit and do none of the work. template <class T> class LinkedList { public: LinkedList(); ~LinkedList() { delete head; } void insert(T* object); void showAll() { head->show(); } private: HeadNode<T> * head; }; template <class T> LinkedList<T>::LinkedList() { head = new HeadNode<T>; } // Delegate to a head node template <class T> void LinkedList<T>::insert(T* pObject) { head->insert(pObject); } // put all these classes to the test int main() { Dog* pDog; Data* pData; int val; LinkedList<Dog> listOfDogs; LinkedList<Data> listOfData; // store user values in a linked list while (true) { std::cout << "What value (0 to stop)? "; std::cin >> val; if (!val) break; pDog = new Dog(val); pData = new Data(val); listOfDogs.insert(pDog); listOfData.insert(pData); } // display the list std::cout << "\n"; listOfDogs.showAll(); std::cout << "\n"; listOfData.showAll(); return 0; }