SDSU 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

  1. Class Templates
    1. Instantiation

Reference


Chapter 7 of Lippman's text

Class Templates


#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;
}



Instantiation

#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

----------