ZeePedia

Class Templates and Nontype Parameters, Templates and Static Members

<< Overloading Template Functions, Template Functions and Objects
Matrices, Design Recipe, Problem Analysis, Design Issues and Class Interface >>
img
CS201 ­ Introduction to Programming
Lecture Handout
Introduction to Programming
Lecture No. 42
Reading Material
Deitel & Deitel - C++ How to Program
Chapter. 12, 20
12.4, 12.5, 12.7, 12.8, 20.1
Summary
68)
Class Templates
69)
Class Templates and Nontype Parameters
70)
Templates and Static Members
71)
Templates and Friend Functions
72)
Example
73)
Sample Program
74)
Advantages and Disadvantages of Templates
75)
Standard Template Library
As discussed earlier, template functions are utilized while writing functions for generic
data type. We take benefit of templates in case of writing the same function repeatedly. In
this case, the writing code seems very similar, in fact identical. But the data type is
changed for different versions. So we write a function for generic data type whose syntax
we have used as under
template <class T>
Here T is a generic data type. Now in the function we write T while dealing with a data
type. This becomes a generic template of the function. During the process of using this
template, this function with a particular data type is called. The compiler automatically
detects the type of the data passed (say we passed an int) and generates a new copy of the
function with int. Here T is written in the original template. The copy is compiled to the
object code while existing in the program. The same thing applies to other data types,
used for the same function. Thus, we create a family of functions with a single template.
The functionality of these functions is the same but with different data types. For
example, if we want to find the square of a number, a template square will be written
first. It will be called with int, double or float. Otherwise, we have to write the over
loaded versions of the square function for different data types. So template functions are
of good use for the programmers. They promote code reuse. The major advantage of their
Page 541
img
CS201 ­ Introduction to Programming
use is that once we write correct code with correct logic for a template function, there
will be no need to re-write it. How can we test a template? We write the template in
reverse technique at the moment. When it is known what the template has to do, we take
a data type for example int. A complete function for int is written and tested. After the
ascertainment of the accuracy of function's working, the int in the function is replaced
with T and declared a template by writing template <class T>. We cannot see the code
generated by the compiler in the editor. So it becomes difficult to debug the template
code. We have to read and check the code carefully while writing it.
After having a detailed discussion on the template function, we will now talk about
template classes.
Class Templates
Creation of a data type of our own with the same behavior for int, float and double etc, is
the case of defining a complete interface and implementation in a generic fashion. To
further understand this concept, let's talk about a data structure called stack. We will now
try to understand how does stack work, what its properties are and can we make it
generic.
You might have seen the plates, kept together in a orderly manner i.e. one on the other.
This is a stack. Now if someone wants to add a plate on the pile, he will have to put it on
the top of the stack. So, there is only one way to add something on the stack. Similarly, if
we want to pick a plate from the pile, it will be taken from the upper-most tier. Thus the
property of the stack is that the last placed thing will be picked first. This phenomenon is
called `Last-in, first out' or LIFO. In programming, we can understand what thing we
want to add, the required thing is added to the top of the stack. When we pick up a thing
from it, the last placed item is picked first. Following this rule of stack (last in first out),
we can make a stack of integers, floats and doubles etc. Here, the stack is a class with a
defined behavior, interface and the data, it holds. Now we say that the data held by the
class is variable to help make a stack of integers, floats or doubles. Thus, stack is a good
candidate for a template class. It means that when we instantiate the class for creating
objects, a stack of integers or floats is required. The behavior of the compiler in template
classes is the same as in template functions. If we want to instantiate a template class
with a new data type, the compiler will generate a new version of the class with the
specific data type at the place of T in the template class.
We know that a class is a user-defined data type. With the help of a template class, we
make another class of the user defined data type. In other words, things are not restricted
to creating copies of class only for native data type. Copies of class of our own data type
can also be created. It is a case of a real extensibility.
Let's see the syntax of this generic template class. It is similar to the simple template
function in which we write template <class T>. Here T is the placeholder that will be
replaced by the data type when we use it. The syntax of the template class is
template <class T>
class class-name()
{
definition of class
Page 542
img
CS201 ­ Introduction to Programming
};
In the definition of the class where the generic data type is required, we write T. For
example, there is a class in which we want to write int data type. The int is the data type
that may be a float or double at different times. For this, T is written wherever we are
using int in the class definition. Be careful that some times, we may use integers as it in a
class. For example, when we create a vector or array, its size will be an integer. But the
array will be of integers, floats or chars. So don't confuse it them. It is better to replace T
whenever necessary.
We start writing of a template with the following line
template <class T>
Later, definition of the class in ordinary fashion begins. We should use T wherever in
case of employing the generic data type. T is not something fixed for this purpose. We
can use a, b or c or whatever needed. However, T is normally used.
The member functions are normally defined out side the class. To define the member
functions of the template class, we write
template <class T>
class name <T>::function name (argument list)
{
// function body
}
In the function body, the programmer will write T wherever it is needed. This way, the
template-class and its member functions are defined. However, when we use the class in
main program or other function, the objects of this class are declared. Suppose there is a
class Number, say Number x; As Number is a template class, we will have to tell the type
of the number. Let's see the code of this simple template class Number. The Number
class can store and display a number. The definition of the class is written as under.
template<class T>
class Number
{
private:
T myNumber;
public:
Number( T n );
display();
};
We create an object of this class in main program by telling the type of the number in the
following way
Number <data type>
Page 543
img
CS201 ­ Introduction to Programming
Here data type may be int, float or double. Now we can create an object of this class for
an integer type as follows.
Number <int> x ;
We can read the line as x is an object of class Number and its parameter is an int. The
way of analyzing it is that wherever we wrote T in the class, now int is written there.
Compiler does it automatically. We will not see the code of this class written for int. The
compiler generates a copy of the class for int and uses it. Similarly, if we write
Number <double> y ;
Here y will be an object with the data member of type double. Again, the entire copy of
the class will be created with double everywhere instead of T. The program will compile
and run. So it is quiet useful and a big shortcut.
Class Templates and Nontype Parameters
There is a little variation, which is we can also use non-type parameters in templates.
What do non-type parameters mean? We have been writing template <class T>.
However, while writing template <class T, int element>, the non-generic type (i.e. int)
will be treated as a constant in the class definition. In the class definition, wherever we
use the name element, it will be replaced by the value passed to it. Arrays when declared
and given a number in square brackets, the number will be a constant. Similarly, while
using with the # sign, we associate a name with a number which is a constant. Here the
non-type parameter in a way behaves like a constant. We can use it to give a dimension to
the things. Instantiating a class, we not only replace T but also provide a value for the
non-type parameter defined in the class definition.
By using templates, we save a lot of effort and labor. The other big motivating factor is
the reuse of tested and tried code for a particular problem.
Templates and Static Members
Now let's talk about the implications of the template classes. To understand the behavior
of templates with static members, we have to comprehend the concept of static member
variables. Static variable members are used to define ordinary classes. The static variable
has a single copy for the whole class. So there are not separate copies of the static data
variable for each object like ordinary data members.
Now let's see what happens when a static member is a part of a template class. The
instantiation of the class has two parts i.e. one is creating an object while the other is the
type of the object. For example, from the previous class Number, we write
Number <int> x ;
Page 544
img
CS201 ­ Introduction to Programming
Here x is an object of generic class Number with a specific type int. We can also use float
or double instead of int. We suppose, there is a static variable in the Number class. On
instantiating the class with int, there will be a copy of static variable for int set-off
objects. If we instantiate the class for float, there is going to be a copy of the static
member for float numbers. So the member is static (i.e. there is one copy) for that type of
the objects. There will be one static value for different object created with type int while
another static value for different objects created for type double. So, this static value is
not class wide. It is something of specific nature. In simple words, the compiler reads the
code of program (main or other function) and generates a copy of the template class
accordingly. It also gives a name of its own to this copy. Thus in a way, the compiler
generates a new unique class, replacing T with int (or any other data type we want). The
static member of this unique class behaves exactly like the ordinary class. Similarly the
compiler generates a copy for double with a unique name. Here the static member of this
copy will affect the objects created for double data type. The static variables are
instantiated once for each type whenever we instantiate a class while replacing generic
data type with a specific data type.
It is pertinent to note that we can replace the generic data type with our own data type.
This is slightly tricky. Suppose, we have written a class, `Person'. There is also a generic
class Array, which can be instantiated with int, float or double data type that means it
may be an array of integers, floats and doubles respectively. Can we do so with an array
of persons? If we have defined a class called Person, there may be an array of Person.
Person now behaves like another data type. At the moment, it does not matter whether
the data type is user defined or not.
We have to be careful that when we are using our own object i.e. our own class in a
template, it must support the functions and interfaces, needed for this generic structure of
the class. So don't put in something that cannot be used by this generic structure. We
have discussed an example of phoneCall where reverse returns x by converting it to ­x. In
that example, we had to define the minus (-) operator for phone call. Similarly, in that
example, billCode is changed to `c'. If number is passed, the negative number will be
returned. Its behavior was changed in phoneCall. So we have to take care of these things.
Whenever we use a template class and instantiate it for one of our own classes, it is
necessary to have compatible function calls in it. It means that member functions behave
properly as per requirements.
Templates and Friend Functions
Now we will have a look on another concept i.e. friend functions. We have read in
classes that a programmer can declare functions as friend of the class. Let's first look at
the need of friend functions. Suppose we have defined an operator for our class, say +
operator. We know that + is a binary operator that takes two arguments. It implements a
+ b. While implementing + operator for a class, we see that the calling object is on the
left side of the operator (i.e. a). The + operator gets this calling object through this
pointer. It has an argument on the right hand side i.e. b. Here, a is an object of our class
and b, an ordinary data type. Similarly, we have a + 2 ; where a is an object of a class
Page 545
img
CS201 ­ Introduction to Programming
and 2, an ordinary int. Now this + operator has to behave intelligently. This way, we have
over loaded it within the class definition. What happens when we say 2 + a ; ? In case of
ordinary integers, 2 + 3 is same as 3 + 2. So we want the same behavior in a class. We
want 2 + a behaving the same way as a+ 2. We cannot carry out overloading of a
member function for this. When we write 2 + a; there will be an int on left- hand side of
the + operator. It is not a member function of the class. For a member function or
member operator, the object on left- hand side should be that of the class. So if we want 2
+ a ; we have to write a friend function for it. Here, the private data of the class is
manipulated by this function. For this purpose, there is need to have access of this
function to the private data of the class. The only way through which an external function
can have access to the private data of the class is declaring that function to be a friend of
the class. So this was the motivation of the friend function.
Now what will be the behavior of friend functions in a template class. For example if we
write in our template class
friend f ();
Here f is function name. Thus in above statement, we say that f is a friend function of the
class. It is declared in a template class. While creating an object of a template class, we
tell the type ( int, float or user defined data type etc) of which the class is to be generated.
Now when we have written friend f(), f becomes a friend function for all classes
generated by using this template. So it is very global that means f will have an access to
the private data structure of any and all different classes which are instantiated by this
template class.
Now we write T in the argument list of the friend function. If we have instantiated a class
for an integer, and we have written the friend function f with T as f <int>. This will mean
that this function is a friend for all int versions of this class. This is an interesting
concept. If we have a double version of the class, this f (i.e. f<int>) will not be a friend of
it. It is only a friend of the integer versions of the class.
Similarly, if we have a friend class declared in the template class as
friend class Y;
then it means that all the member functions of the class Y can access the private data of
any class-type generated with the help of this template. For example, if we generate a
class for int, the member functions of class Y can handle the data structure of the object of
this class of type int. If we instantiate a class for double from this template, the member
functions of Y can handle the data of the object with double version.
Similarly if we write in a template class
friend A :: f ()
Page 546
img
CS201 ­ Introduction to Programming
Here f is a function. It means that the member function f of a class A is a friend of this
template class. We have not granted access to the whole class, but only to a function of
that class. That access applies to all classes generated using this template.
Finally, if we use <T> with the function f, it becomes specific. In other words, this friend
function (i.e. written with <T>) will be a friend of classes generated by the template with
T data type. It will not be a friend of the other versions of the class. Here T may be int,
float, double or any user defined data type.
Example
Let's apply these concepts on one specific example. We may create a class called Stack in
a generic fashion. There are some properties of the stack. Firstly, we should be able to
know that at what position in the stack we are at a particular time. So this is a concept of
stack pointer. We take an array for stack. The stack pointer always points to the top of the
stack. It will be good to make the array generic so that we can make an array of any data
type. Then there are few questions like is stack empty or full etc. Here the code seems
fairly straight- forward. We start with
template class <T>
and then write
class Stack
In the class definition, An integer variable called size is declared for the size of the array.
Then we declare the array and write its data type as T, which is a generic type .It will be
replaced by int, float, double or char when we will use this array. We can use the
dynamic memory allocation for the array. But we use a fixed size array for the sake of
simplicity. To declare an array, we need a constant value. Normally, this constant value is
not written in the class definition. It will go to the constructor and be required when the
constructor will be called for an object. We can use the constructor to actually define the
array for us. We need some utility functions. The function push() is used to push an
element on the stack. We use the function pop() to get an element from the stack. The
push() and pop() functions put and get things of type T. So pop() should return something
of type T. That means it will return int if int is pushed and returns double if double is
pushed and so on. So we need push() and pop() which are parameterized with T. After
this, there is need of some functions for generic manipulation like if stack is full or if
stack is empty. We can write function isempty() that returns a Boolean. If it returns
TRUE, the stack will be empty. However, presence of something in the stack will turn it
FALSE. Similarly we can write a utility function isfull() to check whether the stack is
full. We cannot store elements more than that size in the stack. The isfull() returns TRUE,
if the stack is full. The code of the class definition is very simple. We write T wherever
we need a generic data type. It can be written as under.
template <class T>
class Stack
{
Page 547
img
CS201 ­ Introduction to Programming
private :
int size ;
T array [ ] ;
public :
Stack ( ) ;
void push ( T ) ;
T pop ( ) ;
bool isEmpty ( ) ;
bool isFull ( )
};
In the definition of the functions of the class, we again use <T> immediately after the
name of the class. It will be followed by the resolution operator (::) and the function
name and finally we write T, wherever we want to use generic data type. It's a definition
of the class Stack. While using it, say for int, we write Stack <int> and provide a
initializer value so that it can determine the size of the array. We read it as `create a stack
of type int'. Similarly Stack<double>x will mean x is a stack of type double. The main
advantage of this process is that we write the Stack class once as the behavior is common
regardless of the type of the data we want to put on. Stack class can be used for int,
double or char data type.
This is the analysis of the example of Stack class, now as a programmer, it is left to you
to write the complete code of the example.
Sample Program
Here is a sample program that demonstrates the use of template class.
/* This program defines a template class and shows its use for different data types.
There is also the use of template function. It also overloads the << operator.
*/
#include<iostream.h>
template<class T>
class Generic
{
private:
T instance;
public:
Generic(T i);
void print(void);
};
//generic constructor
template<class T>
Generic<T>::Generic(T i=0)
{
Page 548
img
CS201 ­ Introduction to Programming
instance=i;
}
template<class T>
void Generic<T>::print(void)
{
cout<<"Generic printing: "<<endl;
cout<<instance<<endl;
}
class Employee
{
private:
int idNum;
double salary;
public:
Employee(int id);
friend ostream& operator <<(ostream& out, const Employee &e);
};
Employee::Employee(int id=0)
{
idNum=id;
salary=4.9;
}
ostream& operator<<(ostream &out, const Employee &emp)
{
out<<"Employee number "<<emp.idNum;
out<<" Salary "<<emp.salary;
return(out);
}
void main()
{
Generic<int>anInt(7);
Generic<double>someMoney(6.65);
Generic<Employee> aWorker(333);
anInt.print();
someMoney.print();
aWorker.print();
}
Following is the output of the program.
Page 549
img
CS201 ­ Introduction to Programming
Generic printing:
7
Generic printing:
6.65
Generic printing:
Employee number 333 Salary 4.9
Advantages and Disadvantages of Templates
Although, most of the following uses can also be implemented without templates;
templates do offer several clear advantages not offered by any other techniques:
·  Templates are easier to write than writing several versions of your similar code
for different types. You create only one generic version of your class or function
instead of manually creating specializations.
·  Templates can be easier to understand, since they can provide a straightforward
way of abstracting type information.
·  Templates are type-safe. This is because the types that templates act upon are
known at compile time, so the compiler can perform type checking before errors
occur.
·  Templates help in utilizing compiler optimizations to the
extreme.
Then of course there is room for misuse of the templates. On one hand they provide an
excellent mechanism to create specific type-safe classes from a generic definition with
little overhead. On the other hand, if misused
·  Templates can make code difficult to read and follow depending upon coding
style.
·  They can present seriously confusing syntactical problems esp. when the code is
large and spread over several header and source files.
·  Then, there are times, when templates can "excellently" produce nearly
meaningless compiler errors thus requiring extra care to enforce syntactical and
other design constraints. A common mistake is the angle bracket problem.
Standard Template Library (STL)
Templates are a major code reuse feature. History of C++ language reveals that the
template feature was introduced later, relative to other features. But it is a very important
feature. We will realize that it makes a lot more sense to keep total code base very small
and very concise. It also helps ensure that the same tested code is used everywhere. We
had earlier referred to this concept while writing classes. We separated the interface and
implementation and sealed the implementation after testing it. Afterwards, we created
different objects of the class and every object knew its behavior. Thus there was an
abstraction of details. The template functions and template classes go one-step even
further. With templates, we can perform different tasks while using one base code.
Objects of different types staying with one particular framework can be instantiated. This
framework (template) is so important that a couple of researchers actually sat down and
Page 550
img
CS201 ­ Introduction to Programming
started looking at that in programming we often are using the one concept which applies
to so many things that we should templatise it. For example, with the help of arrays, we
do different manipulations like, `next element', go to the end of the array, add something
at the end etc. Now suppose that the size of array is 100. We want to add the 101st
element in the array. We can do it by copying the same array in a new big array and
adding the element to that array. Thus we have solutions for different problems, but these
are the things of very common use. Their every day use is so important that two
researchers wrote a whole library of common use functions. This library is a part of the
official standard of C++. It is called STL i.e. Standard Template Library. As a library, it
is a tested code base. Some one has written, tested and compiled for the ultimate use of
programmers. We can use these templates and can implement different concepts for our
own data types. Equally is true about the use of the array data type. Our code will become
very small with the use of this tested facility. Similarly, there is no bug or error in it.
Thus, if we have a tested and tried code base, we should try our best to write programs by
using it. STL is a lot of important code, pre-developed for us. It is available as a library.
We can write programs by using it. Thus our programs will be small and error free.
Page 551
Table of Contents:
  1. What is programming
  2. System Software, Application Software, C language
  3. C language: Variables, Data Types, Arithmetic Operators, Precedence of Operators
  4. C++: Examples of Expressions, Use of Operators
  5. Flow Charting, if/else structure, Logical Operators
  6. Repetition Structure (Loop), Overflow Condition, Infinite Loop, Properties of While loop, Flow Chart
  7. Do-While Statement, for Statement, Increment/decrement Operators
  8. Switch Statement, Break Statement, Continue Statement, Rules for structured Programming/Flow Charting
  9. Functions in C: Structure of a Function, Declaration and Definition of a Function
  10. Header Files, Scope of Identifiers, Functions, Call by Value, Call by Reference
  11. Arrays: Initialization of Arrays, Copying Arrays, Linear Search
  12. Character Arrays: Arrays Comparisonm, Sorting Arrays Searching arrays, Functions arrays, Multidimensional Arrays
  13. Array Manipulation, Real World Problem and Design Recipe
  14. Pointers: Declaration of Pointers, Bubble Sort Example, Pointers and Call By Reference
  15. Introduction, Relationship between Pointers and Arrays, Pointer Expressions and Arithmetic, Pointers Comparison, Pointer, String and Arrays
  16. Multi-dimensional Arrays, Pointers to Pointers, Command-line Arguments
  17. String Handling, String Manipulation Functions, Character Handling Functions, String Conversion Functions
  18. Files: Text File Handling, Output File Handling
  19. Sequential Access Files, Random Access Files, Setting the Position in a File, seekg() and tellg() Functions
  20. Structures, Declaration of a Structure, Initializing Structures, Functions and structures, Arrays of structures, sizeof operator
  21. Bit Manipulation Operators, AND Operator, OR Operator, Exclusive OR Operator, NOT Operator Bit Flags Masking Unsigned Integers
  22. Bitwise Manipulation and Assignment Operator, Programming Constructs
  23. Pre-processor, include directive, define directive, Other Preprocessor Directives, Macros
  24. Dynamic Memory Allocation, calloc, malloc, realloc Function, Dangling Pointers
  25. History of C/C++, Structured Programming, Default Function Arguments
  26. Classes and Objects, Structure of a class, Constructor
  27. Classes And Objects, Types of Constructors, Utility Functions, Destructors
  28. Memory Allocation in C++, Operator and Classes, Structures, Function in C++,
  29. Declaration of Friend Functions, Friend Classes
  30. Difference Between References and Pointers, Dangling References
  31. Operator Overloading, Non-member Operator Functions
  32. Overloading Minus Operator, Operators with Date Class, Unary Operators
  33. Assignment Operator, Self Assignmentm, Pointer, Conversions
  34. Dynamic Arrays of Objects, Overloading new and delete Operators
  35. Source and Destination of streams, Formatted Input and Output, Buffered Input/Output
  36. Stream Manipulations, Manipulators, Non Parameterized Manipulators, Formatting Manipulation
  37. Overloading Insertion and Extraction Operators
  38. User Defined Manipulator, Static keyword, Static Objects
  39. Pointers, References, Call by Value, Call by Reference, Dynamic Memory Allocation
  40. Advantages of Objects as Class Members, Structures as Class Members
  41. Overloading Template Functions, Template Functions and Objects
  42. Class Templates and Nontype Parameters, Templates and Static Members
  43. Matrices, Design Recipe, Problem Analysis, Design Issues and Class Interface
  44. Matrix Constructor, Matrix Class, Utility Functions of Matrix, Input, Transpose Function
  45. Operator Functions: Assignment, Addition, Plus-equal, Overloaded Plus, Minus, Multiplication, Insertion and Extraction