The Queue template class contains three assumptions about the QueueItem template parameter. First, the code:
template <class QueueItem> class Queue {
private:
QueueItem buffer[100];
...
};
assumes that QueueItem has a default constructor (i.e., a constructor
that takes no arguments). A default constructor is needed in order to
declare and array of a given type. Classes like Location, Shape, and
Frame that have default constructors can be used to elaborate the
Queue template. However, an error message will result from:
Queue<Message> QueueOfMessages;
Queue<Clock> QueueOfClocks;
because these classes do not have default constructors.
Second, the code:
template <class QueueItem>
void Queue<QueueItem>::Insert(QueueItem item) {
...
buffer[tail] = item;
...
}
assumes that the QueueItem class has an appropriately defined
assignment operator. All classes have a default assignment operator -
a bit-wise copy. In simple classes this is an appropriate assignment
operator. For example, in the case of Queue<int> and
Queue<Location> the default assignment operator is
appropriate. However, the default assignment operator may not be
appropriate for a class that contains pointers as private data.
Third, the code:
template <class QueueItem>
QueueItem Queue<QueueItem>::Remove() {
...
return buffer[val];
}
returns a copy of the object that is in the internal buffer. This code
assumes that an appropriate copy constructor is defined for the class
being substituted for QueueItem.
Other templates make more demanding assumptions about the class or type used to instantiate the template. Consider the following template declaration:
template <class T> class Displayable {
private:
T* displayed;
TextBox* textBox;
public:
Displayable(TextBox* tbox); // testbox to show in
void ShowThis(T* d); // what to show
void Show(); // show current value
void Reset(); // reset displayed from textBox
~Displayable();
};
This template is designed to point to a TextBox in which a current
value will be displayed and from which a new value can be read. The
template also contains a pointer ("displayed") to an object of the template's
parameter type. To achieve its intent, the template must make
assumptions about how the value can be obtained from the displayed
object and how a new value can be given to the displayed object. Since
the type of the displayed object is now know (its type is the
template's parameter), the template code must make assumptions about (impose
constraints on) the type that is used to instantiate the template. The
code for the Displayable template is as follows:
template <class T>
Displayable<T>::Displayable(TextBox *tbox)
{textBox = tbox; displayed = (T*)0;}
template <class T>
Displayable<T>::ShowThis(T* d) { displayed = d; }
template <class T>
Displayable<T>::Show() { textBox->SetText(displayed->ToString()); }
template <class T>
Displayable<T>::Reset() { displayed->FromString(textBox->GetText()); }
template <class T>
Displayable<T>::~Displayable(){}
The Displayable template assumes that the instantiating type has two
methods: