Outline
Other Material
The time, the basic idea is to develop code by leave certain key types unspecified, to be filled in later.
In many ways this is like a parameter that is filled with may different values. Here, however, the parameters are types, and not values.
Generics are used both with functions and with classes.
The following illustrates a simple template function in C++, and its use.
template <class T> T max(T left, T right) {
if (left < right)
return right;
return left;
}
int a = max(3, 27);
double d = max(3.14, 2.75); // see how types differ
class Fraction {
public:
Fraction (int top, int bottom) { t = top; b = bottom; }
int numerator() { return t; }
int denominator() { return b; }
bool operator < (Fraction & right)
{ return t * right.b < right.t * b; }
private:
int t, b;
};
Fraction x(3, 4);
Fraction y(7, 8);
Fraction z = max(x, y);
While template functions are useful, it is more common to use templates with classes.
template <class T> class Box {
public:
Box (T initial) : value(initial) { }
T getValue() { return value; }
setValue (T newValue) { value = newValue; }
private:
T value;
};
Box<int> iBox(7);
cout << iBox.getValue();
7
iBox.setValue(12);
cout << iBox.getValue();
12
Notice how the programmer filled in the template argument when creating a new variable.
iBox.setValue(3.1415); // ERROR - invalid type Box <double> dBox(2.7); cout << dBox.getValue(); 2.7 dBox.setValue(3.1415); cout << dBox.getValue(); 3.1415 iBox = dBox; // ERROR - mismatched types
In the next chapter we will see how generics are used to create collection classes.
Some languages (Eiffel, others) allow the programmer to place a type on the template argument:
class Hash_Table [ H -> Hashable ] ...
The restriction says that the argument (here named H) can only be a subclass of Hashable.
This feature allows the compiler to do stronger type checking, and produce more meaningful error messages.
Remember the class Box. Suppose a class Person has subclasses BoyChild and GirlChild. What is the relationship between Box[Person] and Box[BoyChild]?
Unfortunately, runs into problems with the principle of substitution.
Assume Box[BoyChild] is a subclass of Box[Person], would make the following legal:
Box[Person] aBox = new Box[BoyChild]; Person aGirl = new GirlChild; aBox.set(aGirl);
A similar argument can be made for the reverse.
Can make a similar argument for arrays:
BoyChild [ ] boys = new BoyChild[10]; Person [ ] people = boys; // copy or pointer semantics? GirlChild sally = new GirlChild; people[1] = sally;
If pointer semantics are used for the array assignment then this can produce type errors. Java allows the assignment, but uses a run-time check to catch the last assignment error!
Other languages make the array assignment illegal.