![]() |
|||||||||
7.1 Templates
In each case the same basic algorithms and supporting data structures are needed. What varies among uses of the class is the type of data being manipulated. A good mechanism for dealing with these situations should avoid repetitive programming and preserve the type safety normally expected of a well-designed class. Avoiding repetitive code means that it should not be necessary to implement MouseEventQueue and CharacterQueue as distinct classes when the only difference between them is the type of data contained in their queues. Preserving the type safety means that we do not want to avoid the repetitive code by writing an overly general (type-dumb) class. For example, it is possible to implement a single Queue class that manipulates "void*" types, but this design is overly general because it allows anything to be put into the queue (e.g., MouseEvents in a CharacterQueue). A template is a parameterized class whose parameter denotes the varying type of data. The syntax in C++ to introduce a template for the queue class is as follows: template < class QueueItem > class Queue { ... } Enclosed in the angle brackets after the keyword template is the template parameter. In this example the template parameter, QueueItem, is a class. For a Queue, QueueItem is intended to denote the type of the items that the Queue will hold. The template parameter may be used in the parameterized class (Queue) in one or more of the following ways: to define the argument type of a method in the parameterized class, to define the type returned by a method in the parameterized class, or to define the type of local data that is defined in the parameterized class. These uses of the template parameter are shown in the expansion of the Queue class shown below. In the code for the Queue template class below, QueueItem is first used to define the type of the buffer array, which is used to hold the elements currently in the queue. The parameter of the Insert method is defined as a QueueItem, matching the declaration of the buffer array where the input value will be stored. Finally, the result returned by the Remove method is also of type QueueItem, since this is the type of data extracted from the buffer array.
A parameterized type (template) can be used to create a new class by instantiating the template with an appropriate parameter. The template may be used to create a new class in two ways. The first way directly creates an object as shown here: Queue<int> intQueue; // a queue of integers object In this case, the object intQueue is defined as an instance of the parameterized typed Queue where the parameter is taken as an int type. The second way uses the typedef to define a type (class) name: typedef Queue<int> IntegerQueue; // a class for a queue of integers IntegerQueue intQueue; In either case an object that acts like a queue of integers is created, and can be manipulated in the usual ways. For example, the queue of integers can be tested as follows: intQueue.Insert(100); // add 100 intQueue.Insert(200); // add 200 int x = intQueue.Remove(); // remove 100 intQueue.Insert(300); // queue now has (200,300) int x = intQueue.Size(); // size is 2 Notice that there is no difference in the way the intQueue object is accessed. An object created from an instantiated template is indistinguishable from an object created from a non-parameterized class. To complete the implementation of a template class, each of its methods must be defined. The syntax for a template method must carry a preamble that associates it with the template and with the template's parameters. This leads to the (somewhat wordy) syntax shown in the figure below.
Each method definition is preceded by a template specification (template< class QueueItem>). In addition, the class name contains the template syntax (Queue<QueueItem>::). Note that in the case of the Remove method, the return type comes after the initial template specification and before the class name. The complete code for the parameterized Queue class is shown in the following figure.
Templates also differ from non-parameterized classes in where the method definitions are placed. In non-parameterized classes, the method definitions are put in a code (.cc or .C of .cpp) file. However, for a parameterized class the method definitions are placed in the header (.h) file itself. This is necessary so that when the compiler is asked to elaborate a template (e.g, by seeing a declaration of the form Queue<int>), it need only examine the header file (that has been referenced in a #include statement) to find all of the information that it needs to fully understand how to elaborate the template and generate the code for the required class.
|
|||||||||
|