Introduction to Object Oriented Programming, 3rd Ed

Timothy A. Budd

Chapter 18

Generics

Outline

  1. Generics
  2. Template Functions
    1. Can Even be Used with User Defined Types
  3. Template Classes
    1. Can Be Filled with Different Arguments
  4. Bounded Genericity
  5. Inheritance and Generics
  6. Inheritance and Arrays

Other Material

Intro OOP, Chapter 18, Outline

Generics

The idea of a generic (or template) is yet another approach to software reuse.

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.

Intro OOP, Chapter 18, Slide 01

Template Functions

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
Intro OOP, Chapter 18, Slide 02

Can Even Be Used with User Defined Types

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);
Intro OOP, Chapter 18, Slide 03

Template Classes

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.
Intro OOP, Chapter 18, Slide 04

Can Be Filled with Different Arguments


	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.
Intro OOP, Chapter 18, Slide 05

Bounded Genericity

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.

Intro OOP, Chapter 18, Slide 06

Inheritance and Generics

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.
Intro OOP, Chapter 18, Slide 07

Inheritance and Arrays

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.

Intro OOP, Chapter 18, Slide 08