Contents  1-5  6-11  12-16  17-21  22-27   28-33  34 - 38  39-46  Projects   MFC

   Contact
   Search
   C
   C++
   Visual Basic
   Java
   JavaScript
   DHTML
   Style Sheets
   About
   Active X
   TDC Binding
   PHP
   Perl and CGI
   Flash
   XML
   SQL
   Messages
   Chat
   MCSE
   Linux
   Cabling   
   ActionScript
   Downloads
   E-Cards   
 
    
    


Templates allow you to build type-safe collections.  Templates are sometimes considered superior to linked lists
because linked lists can only handle the particular data objects they were created to work with.  You couldn't place a
different object into a linked list without modifying it.  Templates allow you to teach the compiler how to make a list
of any type of thing, rather than creating a set of type-specific lists.  The type of the thing in the list becomes a parameter to the definition of the class.  The Template class concepts we will deal with are the same as the concepts that cover our standard classes.  So therefore, template instantiation is the act of creating a specific type from a template, and template instances are marked by the individual class data types using the template.  Templates allow you to create a GENERAL CLASS and pass "types" as parameters to that class to build specific instances.  Therefore we can say that a Template is a class that is a parameterized List object.  Are we thoroughly confused now?  Fear not, brave one, this too shall pass. :)  You declare a template by writing:

"Physics is the universe's operating system."  - Steven R Garman
"
Only two things are infinite, the universe and human stupidity, and I'm not sure about the former." - Albert Einstein
 
template <class T>
class List
{
      public:
      List();
     
//full class declaration here
};

The keyword "template" must be used at the beginning of every declaration AND definition of a template class.  The parameters of the template are written after it - they are the items that will change with each instance.  In the expression "template <class T>", the keyword "class" indicates that this is a parameter type and that the identifier, "T", is used throughout the rest of the template definition to refer to the parameterized type (the class).  One instance of this class will substitute "int" wherever "T" appears, another instance will substitute "Monster".  To declare an "int" and "Monster" instance, we would write:

List<int> IntList;            //would create a List of int objects
List<Monster> MonsterList;   
//would create a List of Monster objects

The trick to template design is to get your template working on a single object/class type, then parameterize it, generalizing the template to handle any type of object.  Example:

// File 1 of 2.  This file is a header file called "Template.h"
//  Every class used with the template MUST have a constructor that takes an int, 
//  an "itsSize" data member, and a "GetSize()" accessor.
#include <iostream.h>

class Monster {
        
        public:
 
            Monster() {}
            Monster(int sz) { cout << "Monster created.\n"; }
            ~Monster() { cout << "Monster destroyed.\n"; }

            int GetSize() { return itsSize; }
            void SetSize(int str) { itsSize = str; }

        private:
            int itsSize;
};

/*--------------------------------------------------------------------------------------------*/
template <class T// Declare the template and the generic parameter, "T".  T represents
                                 // whatever object we will pass in to the template. Functions like a typedef
                                 // for multiple classes. This must come directly BEFORE the template class below . 
/*--------------------------------------------------------------------------------------------*/
class GenericArrayOfObjectsTemplate            //The class being parameterized
{
public:
	//Constructor For some "odd" reason, Monsters come in sets of 3
	//Remember what the songs says - "3 is a magic number"... :)
	GenericArrayOfObjectsTemplate(int size = 3) { 
            
           itsSize = size;

              //Below we are saying that pType will become a pointer of whatever type of object
              //we pass in to the template and will point to an array of whatever type
              //of object we pass in to the template.  T is declared a pointer in the private member data.

	   pType = new T[size];

	   for (int i = 0; i < size; i++) {
	        pType[i] = 0; }
	} //close constructor
	//Copy constructor
	GenericArrayOfObjectsTemplate(const GenericArrayOfObjectsTemplate & rhs) {
	       
               itsSize = rhs.GetSize();
	       pType = new T[itsSize];

	       for(int i = 0; i < itsSize; i++) {
	       pType[i] = rhs[i]; }
        } //close copy constructor
	//Destructor
	~GenericArrayOfObjectsTemplate() { delete [] pType; }

	// Overloaded Operator =
	GenericArrayOfObjectsTemplate& operator=(const GenericArrayOfObjectsTemplate &) { 
               
               //Just make sure it's not the object itself trying to copy itself
               if (this == & rhs)
	       return *this;

	       delete [] pType;
	       itsSize = rhs.GetSize();
	       pType = new T[itsSize];

	       for (int i = 0; i < itsSize; i++)
	            pType[i] = rhs[i];

               return *this;
         } //close function
	//2 Overloaded Operator [], one constant and one not
	T & operator[](int offSet) 
            { return pType[offSet]; }

	const T & operator[](int offSet) const
	          { return pType[offSet]; }
	//Accessors
	int GetSize() const { return itsSize; }
	//friend function prototype/declaration. Remember that a friend
	//function must be defined outside the class specification.

	friend void Intrude(GenericArrayOfObjectsTemplate<int>);
private:
        //T represents what this will be a class of - the template
	T *pType;
	int  itsSize;
};

/*--------------------------------------------------------------------------------------------*/
// Friend Function - Intrude  Declared type <int>, can only be used
// with int arrays!   No OTHER data type.  Intrudes into private data.

void Intrude(GenericArrayOfObjectsTemplate<int> theGenericArrayOfObjectsTemplate) {

	cout << "\n*** Intrude <int> Template***\n";

	for(int i = 0; i < theGenericArrayOfObjectsTemplate.itsSize; i++) {
	    cout << "i: " <<    theGenericArrayOfObjectsTemplate.pType[i] << endl;  }

	cout << "\n";
     }

//File 2 of 2.  This file is the source file for main().
#include "Template.h"

void main() {

     GenericArrayOfObjectsTemplate<int>     Test1;
     GenericArrayOfObjectsTemplate<float>   Test2;
     GenericArrayOfObjectsTemplate<long>    Test3;
     GenericArrayOfObjectsTemplate<double>  Test4;
     GenericArrayOfObjectsTemplate<char>    Test5;
     GenericArrayOfObjectsTemplate<Monster> Test6;

     //Can only be used with "int" instances of the template
     Intrude(Test1);

}

Output:

Monster created.
Monster destroyed.
Monster created.
Monster destroyed.
Monster created.
Monster destroyed.
*** Intrude <int> Template***
i: 0
i: 0
i: 0

Monster destroyed.
Monster destroyed.
Monster destroyed.

In the example above, we set up a template class to allow us to create an array of whatever type of objects we pass into it.  In main(), six different objects and class instances are created.  The first five objects are instantiated from built-in types.  The last object is created from our own user-defined class, Monster.  In effect, it is as if we had created six different classes, though we did it with one declared template class, the GenericArrayOfObjectsTemplate.  Also notice that  template <class T> has to come just before the template class itself.  Position and placement of the template declaration keyword matters when declaring and defining template classes.  We made the function, Intrude(), a friend function so that it could be accessed by objects that were not of the class itself.  Remember that a friend function, in addition to using the keyword "friend", must be defined outside the class.  This enables them to circumnavigate restrictions on data members that would otherwise be private or inaccessible to objects that were not of that class or that did not derive from it.  In addition to class templates, we can create function templates:

template <typename T>

void swap(T & x, T & y)
 {
   T tmp = x;
   x = y;
   y = tmp;
 }

int main()
 {
    int i,j;     swap(i,j);  
//Instantiates a swap for int
    float a,b;   swap(a,b);  
//Instantiates a swap for float
    char c,d;    swap(c,d);  
//Instantiates a swap for char
 }

Let's combine a template class and a linked list to handle three different kinds of objects:

#include <iostream.h>
enum { ValueIsSmaller, ValueIsLarger, ValueIsSame};

//--------------------------------------------------------------------------------------------------------------------
// First object class to put into the linked list.  Any class in this linked list must support two methods:
// Show (displays the value) and Compare (returns relative position)

class Data 
{
      public:
      Data(int val):myValue(val){}
      ~Data()
      {
        cout << "Deleting Data object with value: ";
        cout << myValue << ".\n";
      }

      int Compare(const Data &);
      void Show() { cout << "The value of this Data object is " << myValue << ".\n"; }

      private:
      int myValue;
};

//Compare is used to decide where in the list a particular object belongs. 
int Data::Compare(const Data & theOtherObject)
{
    if(myValue < theOtherObject.myValue)
        return ValueIsSmaller;
    if(myValue > theOtherObject.myValue)
        return ValueIsLarger;
    else
        return ValueIsSame;
}
//--------------------------------------------------------------------------------------------------------------------
// Another class to put into the linked list. Again, every class in this linked list
// must support two methods: Show (displays the value) and Compare (returns relative position).

class Monster
{
      public:
      Monster(int strength): mystrength(strength){}
      ~Monster()
      {
         cout << "Deleting the Monster that has strength ";
         cout << (mystrength * 100) << ".\n";
      }

      int Compare(const Monster &);
      void Show()
           { cout << "This Monster has strength " << (mystrength * 100) << "!\n"; }

      private:
      int mystrength;
};

//Compare is used to decide where in the list a particular object belongs. 
int Monster::Compare(const Monster & theOtherMonster)
{
    if(mystrength < theOtherMonster.mystrength)
        return ValueIsSmaller;
    if(mystrength > theOtherMonster.mystrength)
        return ValueIsLarger;
    else
        return
ValueIsSame;
}

//--------------------------------------------------------------------------------------------------------------------
// Another class to put into the linked list. Again, every class in this linked list
// must support two methods: Show (displays the value) and Compare (returns relative position).

class Cat
{
      public:
      Cat(int age): myAge(age){}
      ~Cat()
      {
          cout << "Deleting the Cat that is ";
          cout << myAge << " year(s) old.\n";
      }

      int Compare(const Cat &);
      void Show() 
      { cout << "This cat is " << myAge << " year(s) old!\n"; }

      private:
      int myAge;
};

//Compare is used to decide where in the list a particular object belongs. 
int Cat::Compare(const Cat & theOtherCat)
{
    if(myAge < theOtherCat.myAge)
         return ValueIsSmaller;
    if(myAge > theOtherCat.myAge)
         return ValueIsLarger;
    else
         return
ValueIsSame;
}
//--------------------------------------------------------------------------------------------------------------------
// ADT representing the node object in the list.  As an ADT, it will never
// have a direct instance.  Every derived class must override Insert and Show.


template <class T>
class Node
{
      public:
      Node(){}
      virtual ~Node(){}

      virtual Node * Insert(T * theObject) = 0;
      virtual void Show() = 0;

      private:
};

//--------------------------------------------------------------------------------------------------------------------

template <class T>
class InternalNode: public Node<T>
{
      public:
      InternalNode(T * theObject, Node<T> * next);
      ~InternalNode(){ delete myNext; delete myObject; }

      virtual Node<T> * Insert(T * theObject);
      virtual void Show() 
      { 
              myObject->Show(); 
              myNext->Show(); 
      }
//delegate!

      private:
      T * myObject;    
    //the Object itself
      Node<T> * myNext;
    //points to next node in the linked list
};

//Constructor definitions - all the constructor does is initialize.
template <class T>
InternalNode<T>::InternalNode(T * theObject, Node<T> * next):
myObject(theObject),myNext(next)
{  }


// When you put a new object into the list it is passed to the node which figures out
// where it goes and inserts it into the list.

template <class T>
Node<T> * InternalNode<T>::Insert(T * theObject)
{

           //Is the new value bigger or smaller than me?
        int result = myObject->Compare(*theObject);


        switch(result)
        { 
         
 // by convention if it is the same it comes first
           case ValueIsSame:     
//fall through
           case ValueIsLarger:   
//new Object comes before me
           {
              InternalNode<T> * ObjectNode = new InternalNode<T>(theObject, this);
              return ObjectNode;
           }
           case ValueIsSmaller:
                                     //It is bigger, so pass it on to the next node and let it handle it.
                            myNext = myNext->Insert(theObject);
                            return this;
        }
//close switch

        return this;
}

//--------------------------------------------------------------------------------------------------------------------

//Tail node is just a sentinel
template <class T>
class TailNode : public Node<T>
{
      public:
      TailNode(){}
      ~TailNode(){}

      virtual Node<T> * Insert(T * theObject);
      virtual void Show() { }

      private:

};

//If Object comes to me, it must be inserted before me as I am the tail and NOTHING comes after me.
template <class T>
Node<T> * TailNode<T>::Insert(T * theObject)
{
        InternalNode<T> * ObjectNode = new InternalNode<T>(theObject, this);
        return ObjectNode;
}

//--------------------------------------------------------------------------------------------------------------------

//The Head node has no Object, it just points to the very beginning of the list.
template <class T>
class HeadNode : public Node<T>
{
      public:
      HeadNode();
      ~HeadNode() { delete myNext; }

      virtual Node<T> * Insert(T * theObject);
      virtual void Show() { myNext->Show(); }

      private:
      Node<T> * myNext;
};


//As soon as the head is created, it creates the tail.
template <class T>
HeadNode<T>::HeadNode()
{   myNext = new TailNode<T>;   }


//Nothing comes before the head, so just pass the object on to the next node.
template <class T>
Node<T> * HeadNode<T>::Insert(T * theObject)
{
        myNext = myNext->Insert(theObject);
        return this;
}

//--------------------------------------------------------------------------------------------------------------------

//This class starts the ball rolling and the other classes implement the List.
template <class T>
class LinkedList
{
      public:
      LinkedList();
      ~LinkedList() { delete myHead; }

      void Insert(T * theObject);
      void ShowAll() { myHead->Show(); }

      private:
      HeadNode<T> * myHead;
};

// At birth, LinkedList creates the head node.  The head node then creates the tail node by its
// constructor. So an empty list points to the head which points to the tail and has nothing between.

template <class T>
LinkedList<T>::LinkedList()
{   myHead = new HeadNode<T>;   }


//Delegate the task out to other classes
template <class T>
void LinkedList<T>::Insert(T * pObject)
{   myHead->Insert(pObject);   }

//--------------------------------------------------------------------------------------------------------------------

int main()
{
    Cat * pCat;
    Data * pData;
    int val;

    LinkedList<Cat> ListOfCats;
    LinkedList<Data> ListOfData;

   
//Ask the user to produce some values and put them in the list.
    for(;;)
    {
        cout << "What value? (0 to stop): ";
        cin >> val;

        if(!val)
             break;

        pMonster = new Monster(val);
        pData = new Data(val);
        pCat = new Cat(val);

        ListOfMonsters.Insert(pMonster);
        ListOfData.Insert(pData);
        ListOfCats.Insert(pCat);

    }
//close for loop

  
  //Let ShowAll() iterate through the list and show the object.
    cout << "\n ************ \n";

    ListOfMonsters.ShowAll();

    cout << "\n";

    ListOfData.ShowAll();

    cout << "\n";

    ListOfCats.ShowAll();

    cout << "\n ************ \n\n";

    return 0; 
//On exit, the lists fall out of scope and are destroyed!
}
Output:
What value? (0 to stop): 1
What value? (0 to stop): 2
What value? (0 to stop): 0

************
This Monster has strength 100!
This Monster has strength 200!

The value of this Data object is 1.
The value of this Data object is 2.
This cat is 1 year(s) old!
This cat is 2 year(s) old!

************

Deleting the Cat that is 2 year(s) old.
Deleting the Cat that is 1 year(s) old.
Deleting Data object with value: 2.
Deleting Data object with value: 1.
Deleting the Monster that has strength 200.
Deleting the Monster that has strength 100.

In the template in linked list combination above, the same list can handle three different objects since the Node (ADT), Internal Node, TailNode and HeadNode have been declared as template classes.  Note that each class declaration and method is preceded with "template class <T>".  This tells the compiler that you are parameterizing this list on a type that you will define later when you instantiate the list.  So the declaration of the Node class must now become:

template <class T>
class Node

This says that Node will not exist as a class in and of itself, but rather that you will instantiate Nodes of Monsters, Nodes of Cats and Nodes of Data objects.  The actual type you will pass in is represented by "T".  The InternalNode will now become "InternalNode<T>".  The InternalNode<T> points to a "T" (whatever type of object is passed to it) and a Node<T>, not to a hard-coded Data object and another Node.

The Insert() has been re-defined.  Where there used to be a specific type of object, Data, now there is "T", representing whatever object is passed in.  The parameter is a pointer to "T".  Later, when specific lists are instantiated, the compiler will replace "T" with the corresponding instances of Monster, Data and Cat.  In this way, the InternalNode can continue working indifferent to the actual data type used.  It only asks the objects to compare themselves.  For this reason, each object passed into the template must support two methods:  Show() and Compare().  Depending on the nature of the object's data members, these methods will differ from class to class.  But as long as they are provided, this List can sort any number of generic objects.

You can treat template items just as any other type.  You can pass them as parameters by reference/pointer or by value, and you can return them as return values to functions, also by value or by reference.  Below is a rewrite of main() using the above example, to demonstrate passing template objects by reference and using them in functions.  You will need to include all of the code in the table above up to the main() function.

//Include all of the class declaration code listed in the table above for Monster, Cat, and Data
//objects as well as the ADT Node, and the classes InternalNode, HeadNode, TailNode, and LinkedList.
//Then, just after the LinkesList class, add the code for the two functions and main() below.

//--------------------------------------------------------------------------------------------------------------------

//Function prototypes
void MonsterFunction(LinkedList<Monster> & ListOfMonsters);
void
CatFunction(LinkedList<Cat> & ListOfCats);
void DataFunction(LinkedList<Data> & ListOfData);

//--------------------------------------------------------------------------------------------------------------------

int main()
{
   
//Create instances of the template classes, passing in Monster, Cat and Data
    LinkedList<Monster> ListOfMonsters;
    LinkedList<Cat> ListOfCats;
    LinkedList<Data> ListOfData;

   
//Call the functions
    MonsterFunction(ListOfMonsters);
    CatFunction(ListOfCats);
    DataFunction(ListOfData);

   
//Iterate through the list and show objects

    ListOfMonsters.ShowAll();

    cout << "\n";

    ListOfCats.ShowAll();

    cout << "\n";

    ListOfData.ShowAll();

    cout << "\n ************ \n\n";

    return 0; // The lists fall out of scope and are destroyed!
}

//--------------------------------------------------------------------------------------------------------------------

//Function definitions

void MonsterFunction(LinkedList<Monster> & ListOfMonsters)
{
     Monster * pMonster;
     int val;

       //Ask the user to produce some values, put them in the list.
     for (;;)
     {
        cout << "\nOf what strength is your Monster? (0 to stop): ";
        cin >> val;

        if(!val)
           break;

        pMonster = new Monster(val);
        ListOfMonsters.Insert(pMonster);
     }
//close infinite loop
//close function


void CatFunction(LinkedList<Cat> & ListOfCats)
{
     Cat * pCat;
     int val;

       //Ask the user to produce some values, put them in the list.
     for (;;)
     {
        cout << "\nHow old is your cat? (0 to stop): ";
        cin >> val;

        if(!val)
           break;

        pCat = new Cat(val);
        ListOfCats.Insert(pCat);
     }
//close infinite loop
//close function


void DataFunction(LinkedList<Data> & ListOfData)
{
     Data * pData;
     int val;

       //Ask the user to produce some values and put them in the list.
     for(;;)
     {
         cout << "\nWhat value? (0 to stop): ";
         cin >> val;

         if(!val)
            break;

         pData = new Data(val);
         ListOfData.Insert(pData);
     }
//close infinite loop
}
//close function
Output:
Of what strength is your Monster? (0 to stop): 1

Of what strength is your Monster? (0 to stop): 2

Of what strength is your Monster? (0 to stop): 0

How old is your cat? (0 to stop): 1

How old is your cat? (0 to stop): 2

How old is your cat? (0 to stop): 0

What value? (0 to stop): 1

What value? (0 to stop): 2

What value? (0 to stop): 0
This Monster has strength 100!
This Monster has strength 200!

This cat is 1 year(s) old!
This cat is 2 year(s) old!

The value of this Data object is 1.
The value of this Data object is 2.

************

Deleting Data object with value: 2.
Deleting Data object with value: 1.
Deleting the Cat that is 2 year(s) old.
Deleting the Cat that is 1 year(s) old.
Deleting the Monster that has strength 200.
Deleting the Monster that has strength 100.

Like previous code, but this time LinkedLists are passed by reference to their respective functions for processing.  This can be powerful.  Once lists are instantiated, they can be treated as fully defined types, passed into functions and returned as values.  Each instance of the template is an actual object, and can be used like any other object, as though it were a separate class instance.

STL - The Standard Template Library is offered with most compilers as part of their headers and libraries.  It is a library of template-based container classes, including vectors, lists, queues and stacks.   These group together some common algorithms for sorting and searching.  The essential goal of the STL is to give you an alternative to reinventing the wheel.  You can stand on the shoulders of the programming giants who have come before you.  You can plug STLs into all your programs for specific functions for easier and faster development than if you had to code everything from scratch.  Yes - it is now time to pay homage to our venerable, unappreciated, overworked coding ancestors.  :)  We must send them a "thank you" out across the ether every now and then, as we grimace at their horror stories of misplaced punch cards, Fortran and iron core memory.  To all coding veterans who sailed the murky seas and brackish waters of the dark ages before cheap computers and GUIs to spare,  - we salute you!  Now, back to the STL.  Some of the most useful STL classes and algorithms are listed below with links:


©2004 C. Germany