CS 596 OODP
Template Classess
[To Lecture Notes Index]
San Diego State University -- This page last updated November 16,
1995

Contents of Template Classess Lecture
- Class Templates
- Instantiation
Reference
Chapter 7 of Lippman's text
#include <iostream.h>
template <class Whatever>
class BankAccount
{
public :
Whatever balance;
BankAccount(Whatever amount = 0.0);
};
template <class Whatever>
BankAccount<Whatever>::BankAccount(Whatever amount)
{
balance = amount;
}
class Yen {
public:
Yen ( float StartAmount = 0) {amount = StartAmount ;};
Yen operator +( const Yen& AddMe ) {
return Yen( amount + AddMe.amount ); }
friend ostream& operator<<(ostream& , const
Yen&);
private:
float amount ;
};
ostream& operator<<(ostream& out, const Yen& money)
{
out << "Yen: " << money.amount;
};
main()
{
BankAccount<int> me(10);
BankAccount<Yen> you(200.0);
cout << me.balance << you.balance;
}
Implicit Type Assumptions
#include <iostream.h>
template <class Whatever>
class BankAccount
{
public :
Whatever balance;
BankAccount(Whatever amount = 0.0);
};
template <class Whatever>
BankAccount<Whatever>::BankAccount(Whatever amount)
{
balance = amount;
}
class Yen {
public:
Yen ( float StartAmount = 0) {amount = StartAmount ;};
Yen operator +( const Yen& AddMe ) {
return Yen( amount + AddMe.amount ); }
private:
float amount ;
};
main(){
BankAccount<int> me(10);
cout << me.balance; // Compiles
}
main()
{
BankAccount<Yen> me(10);
cout << me.balance ; // Does not compile
}
Multiple Parameters
template <class TypeA, class TypeB>
class Foo
{
public :
TypeA balance;
TypeB amount;
TypeB bar( TypeA in );
};
template <class TypeA, class TypeB>
TypeB Foo<TypeA, TypeB> :: bar( TypeA in )
{
balance = in;
return amount;
}
#include <iostream.h>
template <class Whatever>
class BankAccount
{
public :
Whatever balance;
static int test;
BankAccount(Whatever amount = 0.0);
};
template <class Whatever>
BankAccount<Whatever>::BankAccount(Whatever amount)
{
balance = amount;
test = amount;
}
template <class Whatever> BankAccount<Whatever> :: test = 0;
main(){
BankAccount<int> me(10);
BankAccount<float> you(20);
BankAccount<int> them(30);
cout << me.test << endl;
cout << you.test << endl;
cout << them.test << endl;
}
Output ( CC )
30
20
30
Special Instances of Operations
#include <iostream.h>
#include <string.h>
template <class Type> class Special {
public :
Type dataMember;
void setData( Type input );
friend ostream& operator << ( ostream&,
Special< Type >& );
};
template <class Type> void Special<Type>::setData( Type input ) {
cout << "In set data" << endl;
dataMember = input;
}
void Special<char*>::setData( char* input ) {
cout << "In char set data" << endl;
dataMember = new char[strlen(input)];
strcpy(dataMember,input);
}
template <class T >
ostream& operator << ( ostream& output, Special< T
>& object) {
output << object.dataMember;
return output;
}
main(){
Special<int> normal; Special<char*> special;
normal.setData(5);
special.setData("Hi Mom");
cout << "normal " << normal << " special " <<
special << endl;
}
Output
In set data
In char set data
normal 5 special Hi Mom
Non-Type Template Types
#include <iostream.h>
template <int Size>
class Board
{
public :
int Squares[Size];
};
main(){
Board<100> large; // OK
const int y = 8;
Board<y> normal; // OK
int x = 10;
Board<x> normal; // Does not compile, needs constant
}
Templates and Inheritance
Template Base and Derived Classes
#include <iostream.h>
template <class Type>
class Top {
public:
Type data;
Top( Type value ) {
data = value;
cout << "Top Construct\n";
};
void setData( Type value) {
data = value;
cout << "In top\n";
};
};
template <class Type>
class Bottom : public Top<Type>{
public:
Bottom( Type value ) : Top<Type>( value) {
cout << "Bottom Construct\n";};
void setNewData( Type value) {
data = value;cout << "In Bottom\n";};
};
main ()
{
Top<int> A( 1);
Bottom<float> B( 3.3);
B.setData( 5.5);
}
Templates and Inheritance
Regular Base and Template Derived Class
class Top {
public:
int data;
Top( int value ) {
data = value;
cout << "Top Construct\n";
};
void setData( int value) {
data = value;
cout << "In top\n";};
};
template <class Type>
class Bottom : public Top {
public:
Type NewData;
Bottom( int A, Type value ) : Top(A) {
cout << "Bottom Construct\n";
NewData = value;};
void setNewData( Type value) {
NewData = value;
cout << "In Bottom\n";};
};
main ()
{
Top A( 1);
Bottom<float> B(2, 3.3);
B.setData( 55);
}Templates and Inheritance
Template Base and Regular Derived Class
template <class Type>
class Top {
public:
Type data;
Top( Type value ) {
data = value;
cout << "Top Construct\n";
};
void setData( Type value) {
data = value;
cout << "In top\n"; };
};
class Bottom : public Top<int> {
public:
float NewData;
Bottom( int A, float value ) : Top<int> (A) {
cout << "Bottom Construct\n";
NewData = value;};
void setNewData( float value) {
NewData = value;
cout << "In Bottom\n";};
};
main ()
{
Top<char> A( 1);
Bottom B(2, 3.3);
B.setData( 55);
}
Finally A Usable Stack
#ifndef _Stack_HH
#define _Stack_HH
#include <iostream.h>
#include <assert.h>
template <class T> // Added
class Stack
{
friend ostream& operator<<(ostream& , Stack&);
public:
Stack(int StartSize = 10);
Stack(const Stack&);
Stack& operator=(const Stack&);
~Stack();
int isEmpty() const;
int isFull() const;
void push(const T& item); // Note change
T& pop(); // Note change
private:
T* stack; // Note change
int topOfStack;
int size;
void grow();
void copyStack(const Stack&);
};
#endif
Using the Template Stack
#include <iostream.h>
#include "Stack.cp"
void main()
{
Stack<int> me;
Stack<float> you;
Stack<char> them;
for (int k = 0; k < 10; k++)
me.push(k);
you.push(11.234);
them.push('w');
cout << me << endl
<< you << endl
<< them << endl;
}
Output
Stack(9,8,7,6,5,4,3,2,1,0)
Stack(11.234)
Stack(w)
Implementation of Stack (1 of 4)
template <class T> Stack<T>::Stack(int StartSize)
{
size = StartSize;
stack = new T[StartSize];
topOfStack = 0;
}
template <class T> Stack<T>::Stack(const Stack<T>&
oldStack)
{
topOfStack = 0;
size = 0;
copyStack(oldStack);
}
template <class T>
Stack<T>& Stack<T>::operator=(const Stack<T>&
oldStack)
{
if (this != &oldStack) {
delete stack;
copyStack(oldStack);
}
return *this;
}
template <class T> Stack<T>::~Stack()
{
delete stack;
}
Implementation of Stack (2 of 4)
template <class T>
int Stack<T>::isEmpty() const
{
if (topOfStack == 0) return 1;
else return 0;
}
template <class T>
int Stack<T>::isFull() const
{ return 0;
}
template <class T>
void Stack<T>::push(const T& item)
{
if (topOfStack == size) grow();
stack[topOfStack++] = item;
}
template <class T>
T& Stack<T>::pop()
{
return stack[--topOfStack];
}
Implementation of Stack (3 of 4)
template <class T>
void Stack<T>::grow()
{
T *oldStack = stack;
int oldSize = size;
size += size/2 + 1;
stack = new T[ size ];
assert(stack != 0 );
// copy elements of old array into new
for ( int ix = 0; ix < oldSize; ++ix )
stack[ ix ] = oldStack[ ix ];
delete oldStack;
}
template <class T>
void Stack<T>::copyStack(const Stack<T>& oldStack)
{
size = oldStack.size;
stack = new T[size];
for (int K = 0; K < oldStack.topOfStack;K++)
push(oldStack.stack[K]);
}
Implementation of Stack (4 of 4)
template <class T>
ostream& operator<<(ostream& output, Stack<T>&
aStack) {
output << "Stack(" ;
output << aStack.stack[aStack.topOfStack - 1];
for (int K = aStack.topOfStack - 2; K>= 0; K--)
output << "," << aStack.stack[K];
output << ")";
return output;
}
Be careful with Templates
This does not compile?WHY?
#include <iostream.h>
#include "Stack.cp"
class foo
{
public:
int name;
};
void main()
{
Stack<foo> bar;
}
Answer
Stack class assumes types implement "<<"
#include <iostream.h>
#include "Stack.cp"
class foo
{
friend ostream& operator<<(ostream&, foo&);
public:
int name;
};
ostream& operator<<(ostream& output, foo& bar )
{
output << "foo(" ;
output << bar.name;
output << ")";
return output;
}
void main()
{
Stack<foo> bar;
}
Why So Complicated?
Smalltalk Stack Equivalent
name: #Stack
superclass: Environment@#Object
classInstanceVars: nil
namedInstanceVars: #(stack)
classPoolVars: nil
initialize
stack := List new.
new
^(super new) initialize
asString
^'Stack(', (stack reverse) asString , ')'
isEmpty
^stack isEmpty
isFull
^False
pop
^stack removeAt: (stack size)
push: item
^stack add: item