Survey
* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project
COSC2767: Object-Oriented
Programming
Haibin Zhu, Ph. D.
Associate Professor of CS,
Nipissing University
1
Lecture 8
The
Polymorphic Variable and
Generics
2
Polymorphic variable
A
polymorphic variable is a variable
that can
hold
values of different types during the
course of execution.
3
Simple Polymorphic
Variables
public class Solitaire {
...
static CardPile allPiles [ ];
...
public void paint(Graphics g) {
for (int i = 0; i < 13; i++)
allPiles[i].display(g);
}
...
4
}
The variable was declared as CardPile, but actually held a number of
different types.
The Receiver Variable
The
most common polymorphic variable
is the one that holds the receiver during
the execution of a method.
Call this in C++ and Java, self in
Smalltalk and Objective-C, current in
Eiffel.
Holds the actual value (the dynamic
class) during execution, not the static
class.
5
The Receiver Variable in
Frameworks
6
The greatest power of the receiver variable comes in
the development of software frameworks.
In a framework, some methods are implemented in
the parent class and not overridden (called
foundation method), others are defined in the parent
class, but intended to be overridden (called deferred
method).
Consider a class Window with subclasses
TextWindow and GraphicsWindow.
The combination of foundation and deferred
methods allow high level algorithms to be reused
and specialized in new situations.
Example, Repainting
Window
7
class Window {
public void repaint () {
// invoke the deferred method paint.
// Because the implicit receiver, this,
// is polymorphic, the method from the
// child class will be executed
paint (graphicsContext);
}
abstract public void paint (Graphics g); // deferred
private Graphics graphicsContext;
}
class GraphicsWindow extends Window {
public void paint (Graphics g) {
// do the appropriate painting job
}
}
Window w= new GraphicsWindow();
w.repaint();
Only the child class knows how to paint the window. The receiver variable is responsible
for remembering the actual class of the receiver when executing the method in the parent
class.
Self and Super
8
In Java and Smalltalk there is another pseudo-variable, named super.
Super is like self, only when a message is given to super it looks for
the method in the parent class of the current class.
class Parent {
void exampleOne () {
System.out.println("In parent method");
}
}
class Child extends Parent {
void exampleOne () {
System.out.println("In child method");
super.exampleOne();
}
}//Super.java
Variable is called base in C#.
Downcast (Reverse
Polymorphism)
9
It is sometimes necessary to undo the assignment to a
polymorphic variable.
That is, to determine the variables true dynamic value,
and assign it to a variable of the appropriate type.
This process is termed down casting, or, since it is
undoing the polymorphic assignment, reverse
polymorphism.
Various different syntaxes are used for this, see the
book.
Parent aVariable = ...;
Child aCard;
if (aVariable instanceof Child)
aChild = (Child) aVariable;
Pure Polymorphism
10
A polymorphic method (also called pure
polymorphism) occurs when a polymorphic variable
is used as an argument. Different effects are formed
by using different types of value.
class StringBuffer {
String append (Object value)
{ return append(value.toString()); }
...
}//PurePoly.java
Note: this is a non-stop method!
Different objects implement toString differently, so
the effects will vary depending upon the argument.
Another Example of Pure
Polymorphism
11
This example is from Smalltalk.
between: low and: high
^ (low <= self) and: [ self <= high]
Different arguments will implement the relational test
differently, so different effects can be achieved.
x between: $a and: $z
x between: 1 and: 100
x between: 3.14 and: 4.56
x between: "abc" and: "pdq"
x between: 10@5 and: 50@40
Summary of Polymorphic
Variables
12
A polymorphic Variable is a variable that can
reference more than one type of object
Polymorphic variables derive their power from
interaction with inheritance, overriding and
substitution.
A common polymorphic variable is the implicit
variable that maintains the receiver during the
execution of a method
Downcasting is the undoing of a polymorphic
assignment
Pure polymorphism occurs when a polymorphic
variable is used as an argument.
Generics
13
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 many different values. Here,
however, the parameters are types, and not
values.
Generics are used both with functions and
with classes.
14
Templates
Templates
give us the means of defining a
family of functions or classes that share
the same functionality but which may differ
with respect to the data type used
internally.
A class template is a framework for
generating the source code for any
number of related classes.
A function template is a framework for
generating related functions.
15
C++ Templates
Function
template
Class template
16
Function Template
template <class T>
return-type function-name(T param)
//one parameter function.
T is called template parameter.
17
Function Templates
A
function can be defined in terms of an
unspecified type.
The compiler generates separate
versions of the function based on the
type of the parameters passed in the
function calls.
18
C++ Template Functions
19
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
template
<class T>
void Display(const T &val)
{ cout << val; }
One parameter function with an additional
parameters which are not template parameters
template <class T>
void Display(const T &val, ostream &os)
{ os << val; }
The
same parameter appear multiple times.
template
<class T>
void Swap(T & x, T &y)
{ ... }
20
One parameter
function
template
Swap
generic
swap
Function Template
...
Swap
2 integers
21
Swap
2 floats
Swap
2 rationals
...
Swap
#include <iostream.h>
template <class TParam>
void Swap( TParam & x, TParam & y )
{
TParam temp;
temp = x;
x = y;
y = temp;
}
22
Swap
class Student {
public:
Student( unsigned id = 0 )
{
idnum = id;
}
int getID() {return idnum;};
private:
unsigned idnum;
};
23
Swap
int main()
{int m = 10;
int n = 20;
Student S1( 1234 );
Student S2( 5678 );
cout << m<<" "<<n<<" "<<endl;
Swap( m, n ); // call with integers
cout << m<<" "<<n<<" "<<endl;
cout << S1.getID()<<" "<<S2.getID()<<" "<<endl;
Swap( S1, S2 ); // call with Students
cout << S1.getID()<<" "<<S2.getID()<<" "<<endl;
return 0;
24 }//swap.cpp
Multiple parameter function
template
template <class T1, T2>
void ArrayInput(T1 array, T2 & count)
{ for (T2 j= 0; j < count; j++)
{cout << “value:”;
cin >> array[j];
}
}
25
Multiple parameter function
template
const unsigned tempCount = 3;
float temperature[tempCount ];
const unsigned stationCount = 4;
int station[stationCount ];
ArrayInput(temperature, tempCount);
ArrayInput(station, stationCount);
26
Example:Table Lookup
#include <iostream.h>
template <class T>
long indexOf( T searchVal, const T * table,
unsigned size )
{
for( unsigned i=0; i < size; i++ )
if( searchVal == table[i] )
return i;
return -1;
}
27
Example:Table Lookup
int main()
{ const unsigned iCount = 10;
const unsigned fCount = 5;
int iTable[iCount] = { 0,10,20,30,40,50,60,70,80,90 };
float fTable[fCount] = { 1.1, 2.2, 3.3, 4.4, 5.5 };
cout << indexOf( 20, iTable, iCount ) << endl; // "2"
cout << indexOf( 2.2f, fTable, fCount ) << endl; // "1"
const unsigned sCount = 5;
char * names[sCount] = { "John","Mary","Sue","Dan","Bob" };
cout << indexOf( "Dan", names, sCount )<<endl; // ?
return 0;
}//funtemplate.cpp
28
Note
In
the function template, if you use a
operator, you must be sure every
class relevant to the template will
support the operator, such as “==“,
etc.
Therefore, C++ provides the
mechanism of operator overloading.
29
Example: student
class Student {
public:
Student( long idVal )
{ id = idVal;
}
int operator ==( const Student & s2 ) const
{ return id == s2.id;
}
private:
long id; // student ID number
};
30
Example: student
int main()
{ const unsigned sCount = 5;
Student sTable[sCount] = { 10000, 11111,
20000, 22222, 30000 };
Student s( 22222 );
cout << indexOf( s, sTable, sCount )<<endl;
// print "3"
return 0;
}//student.cpp
31
Overriding a Function
Template
In
some cases when the function
template does not apply to a particular
type, it may be necessary to either
override
the function template, or
make the type conformant to the function
template.
32
The best matching
principle
Find a function that matches the parameters
well;
If there is no match for a specific function,
find a function template to check if the
parameters match one specialized form; and
If no match is found, the call is declared as
an erroneous one.
If it ends up with two or more equally good
matches, the call is ambiguous and an error
is also reported.
33
Class Template
Declare
and define an object:
template <class T>
class MyClass{
//...
}
MyClass <int> x;
MyClass <student> aStudent;
34
Template Classes
35
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;
};
Can Be Filled with
Different Arguments
Box <int> iBox(7);
iBox.setValue(3.1415);
Box <double> dBox(2.7);
cout << dBox.getValue();
dBox.setValue(3.1415);
cout << dBox.getValue();
iBox = dBox;
36
// ERROR - invalid type
//2.7
//3.1415
// ERROR - mismatched types
In the next chapter we will see how generics
are used to create collection classes.
template <class T1, class T2>
class Circle {
//...
private:
T1 x, y;
T2 radius;
};
//...
Circle <int, long> c1;
Circle <unsigned, float> c2;
37
Simple
Example
Class Template
generic
Array
Class Template
...
integer
Array
38
float
Array
FString
Array
...
Example: Array Class
Template
template <class T>
class Array {
public:
Array( unsigned sz );
~Array();
T & operator[]( unsigned i );
private:
T * values;
unsigned size;
};
39
Example: Array
Class Template
template<class T> Array<T>::Array( unsigned sz )
{ values = new T [sz];
size = sz;
}
template<class T> T & Array<T>::operator[] ( unsigned
i)
{ if( i >= size )
throw RangeError(__FILE__,__LINE__,i);
return values[i];
}
template<class T> Array<T>::~Array()
{ delete [] values;}
40
Example:
Array Class
Template
41
int main()
{ const unsigned numDives = 2;
Array<int> diveNum( numDives );
Array<float> difficulty( numDives );
Array<FString> diveName (numDives);
int j;
for(j = 0; j < numDives; j++)
{cout << "Enter dive #, difficulty level, dive name ";
cin >> diveNum[j] >> difficulty[j] >> ws;
diveName[j].GetLine( cin );
}
for(j = 0; j < 2; j++)
cout << diveName[j] << '\n';
cout << endl;
return 0;
}//array.cpp, Fstring.cpp, Fstring.h, range.h, array.h
Templates and
Inheritances
Template
No
is not a class
inheritances for a template
A
class based on a template is an ordinary
class
class t1 : public Array
{...}//OK!!!
templat <class T>
class Myclass: public Array
{//OK!!!
}
42
Inheritance and Generics
43
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.
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.
44
Templates and static
members
Keep
in mind again:
Template
Static
is not class, only template.
members defined in a template
are static members of the classes of
this template.
45
Java Generics
List
ArrayList
LinkedList
Vector
http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf
46
Java List
47
A List (sometimes called a sequence) is an ordered
Collection that can contain duplicate elements.
Like array indices, List indices are zero based (i.e.,
the first element’s index is zero).
In addition to the methods inherited from Collection,
List provides methods for manipulating elements via
their indices, manipulating a specified range of
elements, searching for elements and getting a
ListIterator to access the elements.
Interface List is implemented by several classes,
including classes ArrayList, LinkedList and Vector.
http://java.sun.com/j2se/1.4.2/docs/api/java/util/List.html
ArrayList and LinkedList
Class ArrayList and Vector are resizable-array
implementations of List.
Class LinkedList is a linked-list implementation of
interface List.
Class ArrayList’s behavior and capabilities are similar
to those of class Vector.
The primary difference between Vector and ArrayList is
that objects of class Vector are synchronized by
default, whereas objects of class ArrayList are not.
//CollectionTest.java
//ListTest.java
http://java.sun.com/j2se/1.5.0/docs/api/java/util/ArrayList.html
http://java.sun.com/j2se/1.4.2/docs/api/java/util/LinkedList.html
48 http://72.5.124.55/j2se/1.4.2/docs/api/java/util/ListIterator.html
ListIterator
49
An iterator for lists that allows the programmer to
traverse the list in either direction, modify the list
during iteration, and obtain the iterator's current
position in the list.
A ListIterator has no current element; its cursor
position always lies between the element that would
be returned by a call to previous() and the element
that would be returned by a call to next().
In a list of length n, there are n+1 valid index values,
from 0 to n, inclusive.
Note that the remove() and set(Object) methods are
not defined in terms of the cursor position; they are
defined to operate on the last element returned by a
call to next() or previous().
http://72.5.124.55/j2se/1.4.2/docs/api/java/util/ListIterator.html
Vector
Like ArrayList, class Vector provides the capabilities of array-like data
structures that can resize themselves dynamically.
Recall that class ArrayList’s behavior and capabilities are similar to
those of class Vector, except that ArrayLists do not provide
synchronization by default. We cover class Vector here primarily
because it is the superclass of class Stack.
At any time, a Vector contains a number of elements that is less than
or equal to its capacity. The capacity is the space that has been
reserved for the Vector’s elements. If a Vector requires additional
capacity, it grows by a capacity increment that you specify or by a
default capacity increment. If you do not specify a capacity increment
or specify one that is less than or equal to zero, the system will double
the size of a Vector each time additional capacity is needed.
//VectorTest.java
http://java.sun.com/j2se/1.4.2/docs/api/java/util/Vector.html
50
Summary
Polymorphic variable
Self,
super, this, base
Generics
Parameterized
classes or functions
Template in C++
Function template
Class template
Java Generics
List
ArrayList
LinkedList
Vector
51
Can Even Be Used with
User Defined Types
52
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);
//fraction.cpp