Cpp - template Template Introduction

Introduction

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.

Template Definition

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.

Demo

#include <iostream> 

class Data//from w w  w . ja va 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;
}

Result

Related Topics