Chapter 15. Templates

As we have seen in the OO chapter, the last concept of object orientation is genericity.

Unfortunately, genericity is a "new" concept.

Genericity in C++ is supported through templates. Templates were added in the ANSI C++ standard (1999). They work on most modern compilers.

Genericity in Java was added in Java 1.5 (2004) through Generics. This is still pretty new.

So what is genericity again?

Genericity is the concept of writing classes that work with any datatype. The dataype is given whenever an object of that class gets instantiated.

Example: Remeber the CarStack, PersonStack and Generic stack:

In C++, Generics are implemented through class templates.

The most prominent use of class templates is in the standard template library (STL)

Here is an example of a class template:

template<class T>
class GenericStack {
private:
  vector<T> items;
public:
  void addItem(T i);
  T removeItem();
};

So, to define a template class

  • Use the keyword "template"

  • In pointy brackets <> define the template parameters. Every template parameter starts with the keyword "class" (or "datatype"), followed by a name of your choice. The most commonly used names are single upper case characters starting with T: T, U, V, ...

  • Inside your class, you can use your template parameters just like other data types (int, float, String, ...)

  • The actual data type is assigned when you "instantiate" this class.

Practice:

Define a generic "Location" class. This class should store two attribtues (x, y) which are of the same datatype, given during its instantiation. Show: The class definition, the attributes, the getter and setter functions for both.

template<class T> class Location {
private:
  T x,y;
public:
  void setX(T newX);  // same for Y
  T getX();           // same for Y
  addSomeThingToX(T addToX) { x = x + addToX; }
};

Default parameters: In the template definition, you may use default parameters. An example is the "basic_string" class from the STL. It defaults to string of the "char" type. Example:

template<class T = char> basic_string ...

Just like default parameters, you may or may not specify these when instantiating. Example:

basic_string s;
basic_string<> s3;  // does not work!
basic_string<char> s2; // same as above
basic_string<int> is;  // does not make much sense
basic_string<wchar> ws;   // wchar may not exist on your system

Which brings us directly to the next part: Instantiating template classes.

You instantiate a template class by using the class name, adding pointy brackets <> and adding the data types. Example:

GenericStack<Car> carStack;
GenericStack<Car *> dynamicCarStack;
GenericStack<Person> personStack;

Practice: Define a variable that instantates your "Location" class with the "int" datatype. Define a variable that instantiates your "Location" class with the "float" datatype.

Location<int> il;
Location<float> fl;

Implementing functions from template classes:

To implement a function from a template class, you have to repeat the template declaration (without default parameters), and add the the same template to the class name. Example:

template <class T>
void GenericStack<T>::addItem(T i) 
{
  ///
}

template <class T>
T GenericStack<T>::removeItem()
{
  ///
}

Practice:

Provide the implementation for the getters and setters from the "Location" class.

template <class T>
void Location<T>::setX(T x)
{
  this->x = x;
}

Caveat:

Templates are not actually instantiated until they are used. They are instantiated once for every datatype used

GenericStack<Car> x;   // instantiates the GenericStack for cars
GenericStack<Car> y;   // resuses that
GenericStack<Person> p; // instantiates the GenericStack for people

Therefore, if you implement them in an extra file they are not instantiated.

Unfortunately every compiler handles this problem differently.

In gcc this can be fixed by putting the implementation into the actual header file!

Note: You can use use templates without classes, for more information see C++ In a Nutshell, pages 174 - 210.