14

Generic Programming and Templates

LEARNING OBJECTIVES

At the end of this chapter, you should be able to understand

  • Using template classes employing template class member functions as well as non-template class member functions.

  • Use type-specific friend functions and static member function and data.

  • Use generic programs extensively for data structure implementation such as stack.

  • Appreciate concepts of developing template libraries.

14.1 Introduction

Generic programming means writing programs that will work for any type of data, i.e. make the programs independent of the type of data. With generic programs, there will be no need to develop type-specific programs for each data type. Templates in C++ are implementation tools provided to write generic programs. For example, a data structure such as stack can be used for storing different types of data such as integers, floats, characters and strings of messages. Using template facility provided by the C++ language, a generic program can be written and stored in a directory and can be used by all programmers for different data types.

14.2 What is Generic Programming and Why Use Templates?

Template is a tool provided by C++ for achieving reusability of code. We can hence say that it is a productivity enhancement tool for the programmer. On many occasions, we come across problems in real life wherein the logic is the same but the data set is different. Suppose that we need a function to sort the given data. The data could be data of integers or data of floats or data of double. Do we write separate functions for each of the data types or is there a tool or method wherein one function takes care of all the data types. Function template is the solution provided by C++.

When we consider the array data structure, do we need to write separate classes for each type of array objects such as array of Students, array of cars, or array of Employees? Class template allows us to write a single class template program and allow us to instantiate several arrays of different groups of objects. Therefore, we can conclude that C++ allows data types to be forwarded to function and class definition at run-time as parameters.

14.3 Template Classes

Suppose that we implement a stack – a last-in-first-out data structure – to store integers. Then we have modified through cut and paste strategy and implemented a stack of floats. Now if we need stack of orders, what shall we do? Keep copying through cut paste! This is not reusability promised by C++. Class templates are very useful when the logic is the same and data sets are different. For example, if we have a class template for Stack class, we can store integers, floats, objects of students on to Stack. Similarly, an array expressed as template allows us to store an array of integers or an array of students, etc. The main advantage of template classes is that if you declare a class template, you can store it in a directory and use these definitions of class templates as and when required in program development, just by creating instances of objects as and when required. It is precisely this concept of reusability that is of immense value to developers. This aspect will be studied in more detail in the next chapter on standard template libraries.

Stack is the most widely used-user defined structure in problem solving. C++ templates allow us to implement a generic Stack<T> template that has a type parameter T. T can be replaced with actual types at run-time, for example, Stack<int>, and C++ will generate the class Stack<int>. We can also create classes such as Stack<float>, Stack<Student> and Stack<char>. Define template once and use it to create classes of different intrinsic and user-defined data types. Incorporating changes is very easy since once the changes are implemented in the template Stack<T>, they are immediately reflected in all classes – Stack<float>, Stack<Student> and Stack<char>. Our next example amplifies these important concepts.

 

Example 14.1: Template Class – Stack

A class template definition is just like a regular class definition. It is preceded by the keyword template. For example, here is the definition of a class template for Stack. Note that T is a parameter value which changes with each instance of class we create. The word class is a keyword that specifies that T is a parameter that will be used to represent the parameter type (T). We can create instances of int, float and Students in the void main section as follows:

   Stack<int> I; //Stack of integers
   Stack<float> F; //Stack of floats
   Stack<Student> stdStack; // Stack of students

Note that we can use Stack<int> or Stack <float>, etc., as data types anywhere in the program just like you use normal data type, for example, to pass arguments, to receive return values, etc. Stack class shown below is like any other class except that parameter type T is used as data type:

   1. template <class T>
   2. class Stack
   3. {public:Stack(); //default constructor
   4. Stack(const Stack&); //Copy constructor
   5. ~Stack(){ delete [] stack_array;} //destructor
   6. Stack& operator=(const Stack&);//Assignment operator
   7. int Size() const;
   8. int empty() const; //returns 1 if stack is empty
   9. T& top(); //returns top of stack
   10. void pop(); //pops top of stack
   11. void push(const T&); //pushes
   12. template<class T>
   13. friend ostream & operator<<(ostream & out1,Stack<T>&S);
   14. private:
   15. T *stack_array; // Stack of data integers,double,students
   16. int tos;
   17. int stack_size; // Stack size
   18. };

Normally, if you declare and define any function, for example, say the constructor Stack within the class itself, like the constructor shown below, then there will be no need to use parameter type T:

   Stack<T> :: Stack() { stack_array = new T[max]; stack_size = max; tos = -1;}
   But if you define outside the class, you have to use qualifiers as shown below:
   template <class T>
   Stack<T> :: Stack(){ stack_array = new T[max]; stack_size = max; tos = -1;}

We define assignment operator as shown below:

   template <class T>
   Stack<T>& Stack<T> :: operator=(const Stack& S)
   { stack_array = new T[S.stack_size];
   tos = S.tos;
   stack_size = S.stack_size;
   for(int i =0 ; i<size; i++)
   stack_array[i] = S.stack_array[i];}
   template <class T> // Size( ) function returns the size of the 
   stack. int Stack<T> :: Size() const { return tos+1;}

Prior to retrieving the data from the top of the stack, we need to ensure that stack is not empty. This is ensured by function empty() shown below:

   template <class T>
   int Stack<T> :: empty() const
   {if(tos == -1) return 1;
   else return 0;}

Push operation in Stack data structure is like adding an element on to the top of the stack. There is a need to increment top of stack ( tos) after each push operation.

  template <class T>
  void Stack<T> :: push(const T& val)
  { if( tos<stack_size-1 )
  { tos++;stack_array[tos] = val; }
  }

In pop operation, we would eject the value from the top of the stack. This we would achieve by decrementing the top of stack (tos)

   template <class T>
   void Stack<T> :: pop()
   {if(tos >= 0)tos--; }
   In top() operation, we would use the value returned by the function for displaying the top of the stack. We would also decrement the tos, after top() operation:
   template <class T>
   T& Stack<T> :: top()
   { return (stack_array[tos--]); }

Also observe that we have declared << operator as friend of Stack class. As we want << operator to be friend of all instances of Stack class, we have declared as a template function as shown below:

   template<class T>
   friend ostream & operator<<(ostream & out1,Stack<T>&S)
   {out1<<”
 	”<<”content”<<endl;
   for ( int j=0 ; j<max; j++)
   out1<<S.top()<<" : ";
   }

Student class is a normal class that is provided to create an instance of students to template class. We would store the roll numbers on to stack, to be extracted on last-in-first-out basis. We have included operator << to be a friend of Student class

   friend ostream & operator<<(ostream &src, Student &S)
   {src<<S.Display(); // to display the roll no of the student
   return src;}

In the next example, we would declare a student class . We would use this class to push instances of students on to Stack. We would also create instances of float Stack and int Stack to demonstrate the utility and power of the template.

 

Example 14.2: stacktemplate1b.cpp Implementation of Stack Data Structure Using Templates

   #include<iostream>
   #include<iomanip>
   using namespace std;
   const int max=10; // declares maximum of array size
   class Student
   {public:
       Student(int roll); // constructor with roll no input
       Student():rollNo(0){} //default constructor
       ~Student() {}; // default destructor
       int Display() const {return rollNo;}
       friend ostream & operator<<(ostream &src, Student &S)
       {src<<S.Display();return src; }
private: int rollNo;
};
Student::Student(int roll):rollNo(roll){}
template <class T>
class Stack
{ public: Stack(); //default constructor
Stack(const Stack&); //Copy constructor
       ~Stack(){ delete [] stack_array;} //destructor
       Stack& operator=(const Stack&);//Assignment operator
       int Size() const;
       int empty() const; //returns 1 if stack is empty
       T& top(); //returns top of stack
       void pop(); //pops top of stack
       void push(const T&); //pushes
       template<class T>
       friend ostream & operator<<(ostream & out1,Stack<T>&S);
private:
       T *stack_array; // Stack of data integers,double,students
       int tos;  //top of stack
       int stack_size; // Stack size
};
template<class T>
ostream & operator<<(ostream & out1,Stack<T>&S)
{out1<<”
 	”<<”content”<<endl;
       for ( int j=0 ; j<max; j++)
       out1<<S.top()<<" : "; }
template <class T> //default constructor
Stack<T> :: Stack()
{stack_array = new T[max]; stack_size = max; tos = -1;}
//copy constructor
template <class T> //copy constructor
Stack<T> :: Stack(const Stack& S): stack_array(new T[S.size]),
   tos(S.tos),stack_size(S.stack_size)
{for(int i =0 ; i<stack_size; i++) stack_array[i] = S.stack_array[i]; }
template <class T>
Stack<T>& Stack<T> :: operator=(const Stack& S)
{  stack_array = new T[S.stack_size];
   tos = S.tos;
   stack_size =S.stack_size;
   for(int i =0 ; i<size; i++)
   stack_array[i] = S.stack_array[i];
}
template <class T>
int Stack<T> :: Size() const { return tos+1;}
template <class T>
int Stack<T> :: empty() const
{if(tos == -1) return 1;
else return 0; }
template <class T>
void Stack<T> :: push(const T& val)
{if( tos<stack_size-1 )
{ tos++;stack_array[tos] = val; }
}
template <class T>
void Stack<T> :: pop()
{if(tos >= 0) tos--; }
template <class T>
T& Stack<T> :: top()
{return (stack_array[tos--]); }
void main()
{Stack<int> I; //Stack of integers
   Stack<float> F; //Stack of floats
   Stack<Student> stdStack;
   for ( int i=0;i<max;i++)
   { I.push(i+10); F.push(i+20); stdStack.push(i+10000); }
   cout<<"
 The contents of the int stack"<<endl;
   cout<<" "<<I;cout<<endl;
   cout<<"
 The contents of the float stack"<<endl;
   cout<<" "<<F; cout<<endl;
   cout<<"
 The RollNos of the Student from stack"<<endl;
   cout<<" "<<stdStack; cout<<endl;
   cout<<"
 endof program"<<endl;
}
/*Output :The contents of the int stack
   Content 19 : 18 : 17 : 16 : 15 : 14 : 13 : 12 : 11 : 10 :
The contents of the float stack
   Content 29 : 28 : 27 : 26 : 25 : 24 : 23 : 22 : 21 : 20 :
The RollNos of the Student from stack
   content10009 : 10008 : 10007 : 10006 : 10005 : 10004 : 10003 : 10002 : 10001 : 10000*/

14.4 Function Templates and Passing of Arguments to a Function

Normal function accepting normal instance of data, for example, a function called FindMax accepting array of integers.

You must pass an integer instance of the array: int FindMax(Array<int> &);

For a function that accepts Student array: void FindMax (Array<Student>&);

A generic template function declaration can handle all kinds of arrays: template <class T> void FindMax( Array<T>& );

A generic template function can also handle parameterized as well particular instances of a template: template <class T> void FindMax(Array<T>& , Array<float>);

14.5 Template Friends

A template class can have friends. These friends can be

  • Non-template friend class or function
  • Template friend class or function
  • Type-specific template friend function

We would refer the reader to Chapter 8 for general functions update. We have also seen in the previous example template friend function as friend operator << to stack template class.

14.5.1 Non-template Function

We can declare a class or function as friend to template class. In the example that follows, we would include a friend function called FindSum() that will add elements of integer array. This program will use a non-template friend function FindSum() that will work only on integer arrays because it is a non-template friend function. We would also create instances of float stack and int stack.

 

Example 14.3: stacktemplate2b.cpp A Non-template Friend Function FindSum() That Will Work Only on Integer Arrays

   #include<iostream>
   using namespace std;
   const int max=10; // declares maximum of array size
   template <class T>
   class Stack
   { public: Stack(); //default constructor
   Stack(const Stack&); //Copy constructor
      ~Stack(){ delete [] stack_array;} //destructor
      Stack& operator=(const Stack&);//Assignment operator
      int Size() const;
      int empty() const; //returns 1 if stack is empty
      T& top(); //returns top of stack
      void pop(); //pops top of stack
      void push(const T&); //pushes
      template<class T>
   friend ostream & operator<<(ostream & out1,Stack<T>&S);
   int FindSum( Stack<int> I ) // I is array of integers
     private: T *stack_array; // Stack of data integers, double, students
       int tos;
       int stack_size; // Stack size
   };
   template<class T>
   ostream & operator<<(ostream & out1,Stack<T>&S)
   {out1<<”
 	”<<”content”<<endl;
       for ( int j=0 ; j<max; j++)
       out1<<S.top()<<" : ";}
   //definition of friend FindSum().Gets access to private data
   int FindSum( Stack<int> I ) // I is array of integers
   { int sum=0;
       for ( int j=0 ; j<max; j++)
          sum+=I.top();
       return sum;
   }
   template <class T> //default constructor
   Stack<T> :: Stack()
   {stack_array = new T[max]; _size = max; = -1; }
   template <class T> //copy constructor
   Stack<T> :: Stack(const Stack& S): stack_array(new T[S.stack_size]),
           tos(S.tos),stack_size(S.stack_size)
   { int i;
       for(i =0 ; i<stack_size; i++)
       stack_array[i] = S.stack_array[i];
   }
   template <class T>
   Stack<T>& Stack<T> :: operator=(const Stack& S)
   { stack_array = new T[S.stack_size];
   tos = S.tos;
   stack_size =S.stack_size;
   for(int i =0 ; i<size; i++)
   stack_array[i] = S.stack_array[i];
   }
   template <class T>
   int Stack<T> :: Size() const { return tos+1;}
   template <class T>
   int Stack<T> :: empty() const
   {if(tos == -1) return 1;
       else return 0;
   }
   template <class T>
   void Stack<T> :: push(const T& val)
   {if( tos<stack_size-1 )
       { tos++;stack_array[tos] = val; }
   }
   template <class T>
   void Stack<T> :: pop()
   {if(tos >= 0) tos--; }
   template <class T>
   T& Stack<T> :: top()
   { return (stack_array[tos--]); }
   void main()
   { Stack<int> I; //Stack of integers
       //populate int stack
       for ( int i=0;i<max;i++)
       {I.push(i+10);}
       cout<<"
 Use friend function int FindSum(Stack<int>)"
            <<"
 to calculate the sum of int Stack"<<endl;
        int sum = FindSum(I);
        cout<<"
 Sum of integer Stack: " << sum<<endl;
        cout<<"
 endof program"<<endl;
   }
   /* Output Use friend function int FindSum(Stack<int>)
   to calculate the sum of int Stack : Sum of integer Stack: 145 */

14.5.2 Template Friend Class or Function

In Example 14.2, we have used extraction operator << as a template friend function of class Stack. In this section, we will introduce another very widely used data structure, i.e. array. Template declaration for Array class is given below:

 

Example 14.4: Template Declaration for Array Class is Given Below

   template <class T>
   class Array
   { public:
      Array(int array_size=max); // constructor
      Array(const Array&); //Copy constructor
      ~Array(){ delete [] array;} //destructor
      Array& operator=(const Array&);//Assignment operator
      T& operator[] (int i) {return array[i];}
      const T& operator[](int i) const {return array[i];}
      int Size() const { return array_size;}
     template<class T>
     friend ostream & operator<<(ostream & out1,Array<T>&S);
     private:
     T *array; // array of data integers,double,students
     int array_size; // array size
   };

Assignment operator =. First we would check if what we have on the left-hand side (lhs) and what we are equating with at the right-hand side (rhs) are one and the same. If same, there is no need to carry out the assignment operation. Hence, we return *this to called function Why return *this? You must appreciate that = operation allows chaining, i.e. we can write statement such as A=B=C=D=25. Then compiler first assigns D=25 and chains to C and thence to B & A. Hence, we need to return reference so that chaining is possible. Then before copying from the rhs, it is a good idea to delete what is on the lhs. Therefore, we use delete *array:

   template <class T>
   Array<T>& Array<T> :: operator=(const Array& S)
   {if( this==&S)
      return *this; // source & destination are same no need for = operation
      delete *array; // delete destination prior to copy from rhs
      array_size=S.Size();
      array=new T[array_size];
      for int i=0;i<array_size;i++)
      array[i]=S[i];
      return *this; // this is for chaining = operator allows chaining
   }

 int Size() const { return array_size;} is public accessory function provided to access private data array_size.

We have also declared << as a friend function of Array class

   template<class T>
     friend ostream & operator<<(ostream & out1,Array<T>&S)
       {out1<<”
 	”<<”Index” <<”		”<<”content”<<endl;
          for ( int j=0 ; j<S.array_size; j++)
              out1<<”
	”<<j<<”		”<<S[j];
   }

Also note that if S[j] pertains to Student class, then it will invoke friend operator << defined in Student class.

   int Display() const {return rollNo;}
   friend ostream & operator<<(ostream &src, Student &S)
   {src<<S.Display();return src; }

We have included overloading of operator [ ] in Array class as shown below:

   T& operator[] (int i) {return array[i];}
   const T& operator[](int i) const {return array[i];}

Please note that array has been declared as pointer belonging to data type T. Given off set or cell number of the array, operator [ ] returns a reference of type T or const T. Because of these overloading operators, we could use statements like

   for ( int i=0;i<I.Size();i++)
    { I[i]=i+10;
      F[i]=i+20.0;
      pstd=new Student(i+10000);
      stdarray[i]=*pstd;
  }

Finally, observe that overloaded friend operator << has allowed us to use statements like cout<<I; in the main program. Student class is a normal class that is provided to create an instance of students to template class. Ex 2 at the end of the chapter gives a complete solution.

14.5.3 Type-specific Friend Function in Class Templates

In the next program, we will use a template friend function FindSum() that will work on all types of arrays because its a template friend function. We will also declare operator << (extraction operator) as friend of Stack class.

Note that we have placed both these functions above public and private declarations in Stack class. Friend in any case gets access to private data. Hence, it can be above public and private declarations of the class. This is one of the ways to declare and define friend functions.

Note further that we have declared friend functions to be type-specific. This means that integer Stack will be a friend of Stack<int> class only. Similarly, float Stack will a be friend of Stack<float class. Hence, we have omitted template <class T> in our friend function definitions.

In the example that follows, we will also show you how to pass the template object as an argument to a function FindSum.

 

Example 14.5: stacktemplate3b.cpp Type-specific Friend Functions

   #include<iostream>
   using namespace std;
   const int max=10; // declares maximum of array size
   template <class T>
   class Stack
   {friend void FindSum( Stack<T> I ) // I is stack of integers
      { T sum=T(0);
      for ( int j=0 ; j<max; j++)
            sum+=I.top();
      cout<< sum<<endl;
   }
   friend ostream & operator<<(ostream & out1,Stack<T>&S)
   {out1<<”
 	”<<”content”<<endl;
      for ( int j=0 ; j<S.Size(); j++)
      out1<<S.top()<<" : ";
           return out1;
   }
   public: Stack(); //default constructor
      Stack(const Stack&); //Copy constructor
      ~Stack(){ delete [] stack_array;} //destructor
      Stack& operator=(const Stack&);//Assignment operator
      oint Size() const;
      int empty() const; //returns 1 if stack is empty
      T& top(); //returns top of stack
      void pop(); //pops top of stack
      void push(const T&); //pushes
      void SetTos(){ tos=max-1;}
   private:
      T *stack_array; // Stack of data integers,double,students
      int tos;
      int stack_size; // Stack size
   };
   template <class T> //default constructor
   Stack<T> :: Stack()
   {stack_array = new T[max]; stack_size = max; tos = -1;}
   template <class T> //copy constructor
   Stack<T> :: Stack(const Stack& S): stack_array(new T[S.stack_size]),
      tos(S.tos),stack_size(S.stack_size)
   { int i;
     for(i =0 ; i<stack_size; i++)
     stack_array[i] = S.stack_array[i];
   }
   template <class T>
   Stack<T>& Stack<T> :: operator=(const Stack& S)
   { stack_array = new T[S.stack_size];
     tos = S.tos;
     stack_size =S.stack_size;
     for(int i =0 ; i<size; i++)
     stack_array[i] = S.stack_array[i];
   }
   template <class T>
   int Stack<T> :: Size() const
   {return tos+1;}
   template <class T>
   int Stack<T> :: empty() const
   {if(tos == -1) return 1;
     else return 0;
   }
   template <class T>
   void Stack<T> :: push(const T& val)
   {if( tos<stack_size-1 )
   { tos++;stack_array[tos] = val; }
   }
   template <class T>
   void Stack<T> :: pop()
   {if(tos >= 0) tos--; }
   template <class T>
   T& Stack<T> :: top()
   { return (stack_array[tos--]); }
   void main()
     {Stack<int> I1; //stack of integers
     Stack<float> F1; //stack of floats
     // fill the data in to all three stacks
     for ( int i=0;i<max;i++)
     { I1.push(i+10);
     F1.push(i+20.0);
   }
   cout<<"
 output using friend << operator"<<endl;
   cout<<"
 The contents of the stack of int type"<<endl; cout<<I1;
   cout <<"
 The contents of the stack of float type"<<endl; cout<<F1;
   //tos() function decrements tos for each display till tos=-1
   //To Go to top of stack Call SetTos() function for reusing Stack
   F1.SetTos(); I1.SetTos();
   cout<<"
Use friend function T FindSum(Stack<T>)"
      <<"
to calculate the sum of T type stack"<<endl;
   cout<<"
 Sum of integer stack : ";FindSum(I1);
   cout<<"
 Sum of float stack : "; FindSum(F1);
   }
   /*Output: out put using friend << operator
   The contents of the stack of int type
       Content 19 : 18 : 17 : 16 : 15 :
   The contents of the stack of float type
       Content 29 : 28 : 27 : 26 : 25 :
   Use friend function T FindSum(Stack<T>)
   to calculate the sum of T type stack
   Sum of integer stack : 145 Sum of float stack : 245 */

14.6 Templates and Static Member Functions and Member Data

While handling static member data and member functions, all the rule that apply to static declarations with respect to ordinary classes also apply for template classes and member functions. Static declaration in template allows each instant of template to have its own static data. For example, if we declare a static member data to stack like numberOfStacks in our array class, then each instantiation of Student array and integer array will have its own numberOfStacks to keep track of how many student arrays or integer arrays have been created.

 

Example 14.6: stacktemplate5b.cpp Program to Demonstrate Static Member

   //functions and static data
   #include<iostream>
   using namespace std;
   const int max=10; // declares maximum of stack size
   class Student
   { public: Student(int roll); // constructor with roll no input
            Student():rollNo(0){} //default constructor
            ~Student() {}; // default destructor
       private: int rollNo;
   };
   Student::Student(int roll):rollNo(roll){}
   template <class T>
   class Stack
   {friend void FindSum( Stack<T> I ) // I is stack of integers
   {  T sum=T(0);
       for ( int j=0 ; j<max; j++) sum+=I.top();
       cout<< sum<<endl;
   }
   friend ostream & operator<<(ostream & out1,Stack<T>&S)
   {out1<<”
 	”<<”content”<<endl;
       for ( int j=0 ; j<S.Size(); j++)
       out1<<S.top()<<" : ";
       return out1;
   }
   public: Stack(); //default constructor
       Stack(const Stack&); //Copy constructor
       ~Stack(){ delete [] stack_array;} //destructor
       Stack& operator=(const Stack&);//Assignment operator
       int Size() const;
       int empty() const; //returns 1 if stack is empty
       T& top(); //returns top of stack
       void pop(); //pops top of stack
       void push(const T&); //pushes
       void SetTos(){ tos=max-1;} // To go to top of stack
       static int GetNumberOfStacks() { return numOfStacks;}
   private:
       T *stack_array; // Stack of data integers,double,students
       int tos;
       int stack_size; // Stack size
       static int numOfStacks; // static data to keep track of number of stacks
   };
   // template instantiation of static member
   template < class T>
   int Stack<T>::numOfStacks=0;
   template <class T> //default constructor
   Stack<T> :: Stack()
   {  stack_array = new T[max];
       stack_size = max;
       tos = -1;
       numOfStacks++;
   }
   template <class T> //copy constructor
   Stack<T> :: Stack(const Stack& S): stack_array(new T[S.stack_size]),
           tos(S.tos),stack_size(S.stack_size)
   { int i;
       for(i =0 ; i<stack_size; i++)
       stack_array[i] = S.stack_array[i];
            numOfStacks++;
   }
   template <class T>
   Stack<T>& Stack<T> :: operator=(const Stack& S)
   { stack_array = new T[S.stack_size];
      tos = S.tos;
      stack_size =S.stack_size;
      for(int i =0 ; i<size; i++)
      stack_array[i] = S.stack_array[i];
   }
   template <class T>
   int Stack<T> :: Size() const { return tos+1;}
   template <class T>
   int Stack<T> :: empty() const
   {if(tos == -1) return 1;
      else return 0;
   }
   template <class T>
   void Stack<T> :: push(const T& val)
   {if( tos<stack_size-1 )
      { tos++;stack_array[tos] = val; }
   }
   template <class T>
   void Stack<T> :: pop()
   {if(tos >= 0) tos--; }
   template <class T>
   T& Stack<T> :: top()
   { return (stack_array[tos--]); }
   void main()
   { Stack<int> I1; //stack of integers
      Stack<float> F1; //stack of floats
      Stack<Student> stdStack; // stack of Students
      // fill the data in to all three stacks
      for ( int i=0;i<max;i++)
      {I1.push(i+10); F1.push(i+20.0); stdStack.push(i+10000);
      }
      // declare & fill the data in Second set of Stacks
      Stack<int> I2; //Stack of integers
      Stack<float> F2; //Stack of floats
      Stack<Student> stdStack2; // Stack of students
      // fill the data in to all three stacks for second set
      for ( i=0;i<I2.Size();i++)
      { I2.push(i+10); F2.push(i+20.0); stdStack2.push(i+10000);
      }
      cout<<"
 Display static data using full class specification.."<<endl;
      cout<<"
 integers Stacks"<<"	"<<Stack<int>::GetNumberOf Stacks()<<endl;
      cout<<" float Stacks"<<"	"<<"	"<<Stack<float>::GetNumberOf Stacks()<<endl;
      cout<<" Student Stacks"<<"	"<<Stack<Student>::GetNumberOf Stacks()<<endl;
      cout<<"
 Display static data using object say I2 , F2 , stdStack2.." <<endl;
      cout<<"
 integers Stacks"<<"	"<<I2.GetNumberOfStacks()<<endl;
      cout<<" float Stacks"<<"	"<<"	"<<F2.GetNumberOfStacks() <<endl;
      cout<<" Student Stacks"<<"	"<<stdStack2.GetNumberOfStacks() <<endl;
   }
   /*Output Display static data using full class specification.
   integers Stacks 2
   float Stacks 2
   Student Stacks 2
   Display static data using object say I2 , F2 , stdStack2..
   integers Stacks 2
   float Stacks 2
   Student Stacks 2*/

14.7 Template Exceptions

For dealing with exceptions while using in conjunction with templates, the programmer has the following options:

  • Declare the exception class outside the template class.
  • Declare the exception inside the template class.

Recall from Chapter 11 on exceptions tha t we have defined an exception class stackfullexception {} and stackemptyexception {} with an empty body with in the class definition so that we could use it as a tool to catch the exception and enter the catch block. The catch block, then, informs the user and makes necessary rectification or exits the program. Note that this exception class has no body. Its sole purpose is to give entry to catch block. As an example, while programming Stack operations, we can include two exceptions, namely, stackfullexception and stackemptyexception, within the template class Stack as shown below:


  class Stack
   {public: ………………….
   // Exception classes
      class stackfullerror {};
      class stackemptyerror {}
   };

When an exception object is thrown, control passes to catch block wherein corrective mechanisms are in place. Note that we have to use Stack<string> as we are using templates and string specifies the parameter type.


   catch(Stack<string>::stackfullerror)
      { cout<<”
stack full exception . Cannot be pushed on to stack:”<<endl;
  cout<<”
Exiting the catch block of stackfull exception ..”<<endl;
  }
  Ex 3 at the end of the chapter gives complete solution.

14.8 Summary

  1. Generic programming means writing programs that will work for any type of data, i.e. make the programs independent of type of data.
  2. Template is a tool provided by C++ for achieving reusability of code.
  3. Class templates are very useful when the logic is the same and data sets are different.
  4. A generic template function declaration can handle all kinds of arrays template <class T>void FindMax( Array<T>& ).
  5. A generic template function can also handle parameterized as well particular instances of a template: template <class T> void FindMax( Array<T>& , Array<float>).
  6. A template class can have friends viz non-template friend class or function, template friend class or function, or type-specific template friend function.
  7. We can declare a class or function as a friend to template class.
  8. We can also declare a type-specific friend function in class templates.
  9. Template classes can have static member functions and member data.
  10. Template classes can have exception classes also.

Exercise Questions

Objective Questions

  1. Generic programming means
    1. Program independence
    2. Data-type independence
    3. Hardware independence
    4. Language independence
  2. Generic programming relies on the concept of
    1. Data binding
    2. Abstraction
    3. Polymorphism
    4. Encapsulation
  3. Templates in C++ achieves
    1. Inheritance
    2. reusability
    3. Run-time polymorphism
    4. Data hiding
    1. ii
    2. i and ii
    3. i, ii and iii
    4. i and iv
  4. Creating a specific type of template is called
    1. Objectization
    2. Instantiating
    3. Parameterization
    4. Serialization
  5. Templates are useful when
    1. Logic and data are the same
    2. Logic is the same and data are different
    3. Logic and data differ
    4. In all above cases
  6. In template declaration: template < class T > class & T imply
    1. T is a parameter used
    2. T is an object of class
    3. Class is identifier of parameter of type T
    4. T is a parameterized identifier used throughout the program
  7. If a function is declared and defined within the class there is no need to use parameter type T.     TRUE/FALSE
  8. If a function is declared and defined outside the class, there is no need to use parameter type T.     TRUE/FALSE
  9. Passing a stack object to a function FindMax that is accepting Student stack as parameter, the prototype declaration can be written as
    1. void FindMax ( Stack <T> & );
    2. void FindMax ( Stack & );
    3. void FindMax ( Stack <Student> & );
    4. void FindMax ( Student <Stack> & );
  10. Correct syntax for declaring a inline template function is
    1. Template < class T> inline FindMax(Stack <T> &)
    2. Inline template < class T> FindMax(Stack <T> &)
    3. Any of a and b
    4. None of a and b
  11. When class has static member functions and a private static member data, each instant of class will have its own static member.     TRUE/FALSE
  12. A generic template function cannot be made specialized template function by overriding the function with a specific type of argument template function.     TRUE/FALSE

    Short-answer Questions

  13. Distinguish between template and macro.
  14. Differentiate function arguments and template arguments.
  15. What is parameterization? Explain with examples.
  16. How many types of friend declarations are possible with templates? Explain with examples.
  17. Distinguish specific and general friends in case of template functions.
  18. How do you pass template class as argument to a template function and non-template function?
  19. Explain static member function and static member data usage in a template class declaration.

    Long-answer Questions

  20. Explain the syntax for declaring a template function within a class definition and outside a class definition.
  21. Explain assignment operator and extraction operator working with class templates with example data structure array.
  22. How do templates handle friend functions? Explain with examples.
  23. How do templates handle static member functions and data?
  24. Discuss the syntax for handling exceptions inside a template.

    Assignment Questions

  25. Implement == operator for Stack class discussed in the chapter.
  26. Implement exception classes ArrayOutOfBound(){} and IOError(0{} for Array class discussed in the chapter. Include exception within template class and also outside the template class.
  27. Expand the definition of Array class to include functionality such as Travesre(), Insert() and Delete(), and sort () with exception handling mechanism. Catch block should reallocate the memory double the size of the original allotment; copy the contents into enlarged array and resume the porgram.
  28. Write a template based cpp for Queue class. Include operators for ==, << and ++ to indicate servicing of next element in the Queue. Include functionality such as Display() and Enqueue() to insert in the end of the Queue, Dequeue () to service the first element by displaying the element.
  29. Write a template based cpp for LinkedList class. Include operators for ==, << and ++ to indicate servicing of next element in the Linked List. Include functionality such as Display() and AddFront() to insert in the front of the LinkedList, FindElem() to find the element given the position and element value.

Solutions to Objective Questions

  1. b
  2. c
  3. c
  4. b
  5. b
  6. d
  7. True
  8. False
  9. c
  10. a
  11. True
  12. False
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.139.83.199