CE00314-2 Further Programming Concepts in C++ Lecture 6 Collections & Templates

Preview:

Citation preview

CE00314-2Further Programming Concepts in C++

Lecture 6

Collections & Templates

Introduction

Part 1 Collections Static - Dynamic Template definition Function templates Class templates

Part 2 Adaptable collections Further inheritance

Collections

Arrays Dynamic collections

Linked lists Constructed within application (specific) Generic linked list class Template implementation of generic l. list

Standard Template Library contains Vectors Linked Lists Other STLs

Array of accounts Array initialisation

int b[5] = {75,25,100,-45,60};

Account acct[3] = {Account(500,5,0.6), Account(), Account(100.0) };

COLLECTIONS

An array of various accounts

main(){Savings acc1(100.0);Time acc2(500.0, 100.0);Investment acc3(101.5, 6.5);

Account* staffacct[3] = { &acc1, &acc2, &acc3}

for(i = 0; i<3; i++){

staffacct[i]->print();}

Arrays and new

Arrays can be created with new int* p = new int[10]; elements are accessed using subscripts

p[0],p[1] ... similarly for objects:

Account * acs = new Account[20];cout<< acs[0]->balance();

Deleting Objects

Once an object created with new is finished it can be destroyed using delete

delete ac1; If the pointer points to an array it is necessary

to tell C++ this by writing: delete [ ] p;

Dynamic Collections

• Arrays are a fixed size although can be resized dynamically by using memory management features used in C

• Dynamic structres ccccna be used to allow collection to shrink and grow dynamically

• Different implementations exist

Comparing Implementations

Fixed size versus dynamic size A statically allocated array

Prevents the enqueue operation from adding an item to the queue if the array is full

A resizable array or a reference-based implementation

Does not impose this restriction on the enqueue operation

Comparing Implementations

Pointer-based implementations A linked list implementation

More efficient The ADT list implementation

Simpler to write

A Summary of Position-Oriented ADTs Position-oriented ADTs

List Stack Queue

Stacks and queues Only the end positions can be accessed

Lists All positions can be accessed

A Summary of Position-Oriented ADTs Stacks and queues are very similar

Operations of stacks and queues can be paired off as

createStack and createQueue Stack isEmpty and queue isEmpty push and enqueue pop and dequeue Stack getTop and queue getFront

A Summary of Position-Oriented ADTs ADT list operations generalize stack and

queue operations– getLength– insert– remove– retrieve

ADT objects

Rely on use of an Abstract Class which contains the referencing mechanism and allows objects to be included in the collections.

ABSTRACT BASE CLASSES

class Object{

public: Object(){;}

virtual ~Object(){;}virtual ostream& printOn(ostream&) const = 0;friend ostream& operator<<(ostream& out,

const Object& ob){

ob.printOn(out);return out;

}}

A linked List

class Entry{

public:

Entry *next;

Object *info;

Entry( Object *obj ) {info = obj; next = 0; }

~Entry() { if( ! (info==0) ) delete info; }

};

Use this as data for linked listclass List

{

private:

Entry *head;

int NoEntries;

public:

List() { head = 0; NoEntries=0;}

~List();

linked list cont.

Entry* returnHead() const { return head ;}

void add( Object& );

int isEmpty(){return head == 0;}

};

Linked list

void List::add( Object& newEntry )

{

Entry *newElement = new Entry( &newEntry );

newElement->next = head;

head = newElement;

NoEntries++;

}

Destructor

List::~List(){while(head != 0){

Entry* temp = head;head = head-> next;delete temp;

}}

Container Class

As can be seen form the previous example the object is a Node which is part of a list

The list is an example of a container class

Container Classes Container classes are an important category of ADTs

They are used to maintain collections of elements like stacks, queues, linked lists, tables,trees, etc.

Container classes form the basis for various C++ class libraries C++ container classes can be implemented using several

methods: Ad hoc, rewrite from scratch each time A generic class facility (eg. list class with list nodes) Parameterised Types (use of templates to generalise the class) void Pointer Method (allows heterogenous collections)

Example Pointer Method

Generic ADT List container class 4 basic operations

Insert Membership (e.g. IsInList) Removal Iteration (e.g. Display routine)

Example ApplicationsGeneric List.h

#ifndef Generic List

#define Generic List

class List {

public:

List (void);

~List (void);

void remove current (void);

// Used as iterators: : :

void reset (void);

void next (void);

protected:

class Node f

friend List;

public:

Node (void *, Node *n = 0);

~Node (void);

void add to front (void *);

void add to end (void *);

Node *remove (void *);

private:

void *element ; // Pointer to actual data

Node *next ;};

Generic List.h (cont'd)

protected:

// used by subclasses for implementation

void add to end (void *);

void add to front (void *);

Node *current value (void);

void *current (void);

bool includes (void *);

void *remove (void *);

// important to make match virtual!

virtual bool match (void *, void *);

private:

Node *head ;

Node *iter ; // used to iterate over lists

};

// Iterator functions

inline List::Node *List::current value (void) {

return this->iter ;

}

inline void List::reset (void) {

this->iter = this->head ;

}

inline void *List::current (void) {

if (this->iter )

return this->iter ->element ;

else

return 0;

}

inline void List::next (void) {

this->iter = this->iter->next ;

}

Class templates Class templates enable reusable data types to

be easily created Often called generic programming

For example we can create a generic stack (a last in first out data structure) using class templates The generic stack can be instantiated with any

data type Stack of integers, stack of doubles, stack of

dates etc

// Stack class template// Stack class templatetemplate <class T> class Stacktemplate <class T> class Stack{{

private:private:int size;int size; // No. of elements in // No. of elements in

the stackthe stackint top;int top; // Location of the top element// Location of the top elementT* stackPtr;T* stackPtr; // Pointer to the stack// Pointer to the stack

public:public:Stack(int);Stack(int);~Stack() { delete[] stackPtr; }~Stack() { delete[] stackPtr; }int push(const T&);int push(const T&); // Push an element// Push an elementint pop(T&);int pop(T&); // Pop an // Pop an

elementelementint isEmpty() { return top==-1;}int isEmpty() { return top==-1;}int isFull() { return top==size-1;}int isFull() { return top==size-1;}

};};

void main()void main(){{

Stack<char> charStack(7);Stack<char> charStack(7);char[] name=“Michael”;char[] name=“Michael”;

int j=0;int j=0;while(charStack.push(name[j])while(charStack.push(name[j])

j++;j++;

char c;char c;cout << “My name in reverse is : “;cout << “My name in reverse is : “;while(charStack.pop(c))while(charStack.pop(c))

cout << c;cout << c;

}}

This code assumes that overloaded assignment operator function exist for programmer defined data types This must be provided if the object used with

the Stack class contains dynamically allocated memory

Template Definition

Cambridge Dictionary template  1 a pattern made of metal, plastic or paper, which is used for making many copies of a shape or to help cut material accurately

2 a system that helps you arrange information on a computer screen

C++ Pattern for handling generic data

Function overloading

Swap revisited To handle integers

void swap(int& rnA, int& rnB){ int nTemp;

nTemp = rnA; rnA = rnB;

rnB = nTemp}

Function overloading

Swap revisited To handle characters

void swap(char& rnA, char& rnB){ char nTemp;

nTemp = rnA; rnA = rnB;

rnB = nTemp}

Function overloading

Swap revisited float, double ……. Separate functions for each ??

Generic function Generic functionality Generic data – automatically typed when used Template function

Template function

Conceptually

void swap(Type_of_Var& Var1, Type_of_Var& Var2){ Type_of_Var Temp; Temp = Var1; Var1 = Var2; Var2 = Temp;}

Template Function - syntax

template<class T> // template prefixvoid swapValues(T& Var1, T& Var2){

T Temp;Temp = Var1;Var1 = Var2;Var2 = Temp;

}

For demonstration see – Template1.cpp

Template functions - array print Handling unspecified arrays Array length?

template<class T>void printArray(const T *array, const int nSize){

for(int nCount = 0; nCount < nSize; nCount++)

cout << array[nCount] << “ “;

cout << endl;}

For usage example see – Template2.cpp

Template Functions - returningAlso possible to have generic return

template<class T>

T addValues(T Val1, T Val2)

{

return Val1 + Val2;

}

See Template3.cpp for usage example

Template Functions – multiple types Possible to have more than one type

template<class T1, class T2> Must use all parameters All must be utilised within function See Template4.cpp

Possible to use Tx for casting and return type See Template5.cpp

Template functions - Plenary

Produce generic solution Data types provided at run time Operators must be able to handle types Overloaded operators included Use of keyword “class” can be replaced with

“typename” ANSI/ISO standard allows Programmers tend to use “class”

Class Templates

Syntax basically the same as when using function templates must use keyword “class”

template<class T>class Pair{private:

T first;T second;

private:Pair();Pair(T Val1, T Val2);

etc….. See Template6.cpp for further details

Class templates

So far….. Class within main file Could place within .h file

and include See Template7.cpp

Shows use of Array of pointers ? – mixed types?

Creating function templates from class templates We can easily create a function template

by passing a class template as an argument to a function A classic example is a sort() function template

which sorts the contents of a container template (for example and array) passed as an argument

We can then create a sort() function template

template<class T> void sort(Vector<T>& v)template<class T> void sort(Vector<T>& v){{

// sort the elements of v into increasing// sort the elements of v into increasing// order using a bubble sort// order using a bubble sort

  int size=v.getSize();int size=v.getSize();for (int i=0; i<size-1; i++)for (int i=0; i<size-1; i++)

for (int j=size; i<j; j--)for (int j=size; i<j; j--)if (v[j]<v[j-1])if (v[j]<v[j-1]) // swap v[j] & // swap v[j] &

v[i]v[i]{{

T t = v[j];T t = v[j];v[j]=v[j-1];v[j]=v[j-1];v[j-1] = t;v[j-1] = t;

}}}}

void main()void main(){{

Vector<int>& vi(100);Vector<int>& vi(100);Vector<char*>& vc(100);Vector<char*>& vc(100);Vector<float>& vf(100);Vector<float>& vf(100);Vector<Circle>& vci(100);Vector<Circle>& vci(100);

// initialize the vectors// initialize the vectors// …..// …..

..sort(vi);sort(vi);sort(vc);sort(vc);sort(vf);sort(vf);sort(vci);sort(vci);

}}

The compiler will try and create the correct sort() functions by instantiating the templated functions

It will run into 2 problems in this example Instantiating sort() with a char* (a string) argument will

produce incorrect results The ‘<‘ operator will not test for alphabetical

ordering of the strings Instantiating sort() with a Circle object argument will

produce a compilation error We need an overloaded operator<() function

defined on Circle objects

We can also create an operator<() function for Circle objects

int operator < (Circle& c1,Circel& c2)int operator < (Circle& c1,Circel& c2){{return c1.radius<c2.radius;return c1.radius<c2.radius;}}

Other features of templates

Templates and friends With templates, friendship can be established

between either a class template or a particular instantiation of the template and global/member functions or entire classes

A few examples will clarify this:

Declare a function f() to be a friend of every class specialization of class template X

Declare every member function of class Y to be a friend of every class specialization of class template X

template<class T> class Xtemplate<class T> class X{{

……..friend void f();friend void f();……..

}}

template<class T> class Xtemplate<class T> class X{{

……..friend class Y;friend class Y;……..

}}

The Standard Template Library (STL)

The Standard Template Library (STL) is an addition to the C++ Standard Library

Developed at the Hewlett-Packard Labs in the mid-late 90’s

STL defines powerful, template-based, reuseable components that implement many common data structures and algorithms to process those data structures

STL is extremely complex, being optimised for efficiency.

STL is based on 3 components

Containers

Iterators

Algorithms

Template-based containers are data structures used to group objects of any type

Examples include linked lists, vectors and sets

Iterators encapsulate the mechanisms used to access container elements

A simple pointer can be used as an iterator for a standard array

Algorithms are functions that perform common manipulations on containers

Examples include searching and sorting algorithms There are around 70 algorithms implemented in the

STL A key aspect of the STL is that an algorithm can be applied

to a container without regard to the exact implementation of the container The container’s iterator just has to support the

minimum requirement of the algorithm This means that programmers can write one algorithm

which can be applied to multiple containers

Examples of sequence STL containers include vector

Provides random access with constant time insertions and deletions at the end

deque (double entry queue) Provides random access with constant

time insertions and deletions at the beginning and the end

list Provides linear time access but constant

time insertions and deletions at any position in the list

Examples of associative STL containers include set

Provides rapid lookup (set membership), no duplicates around

multiset As above but allows duplicates

Iterators

Iterators allow generic algorithms to ‘plug in’ to different containers As long as the container supports the iterator

that the algorithm uses to access container elements, the algorithm can be applied to it

There are different classes of iterator to support things like linear or random access

However, certain iterator operations are uniform and can be applied to all containers

* (de-referencing) allows access to the element to pointer to by the iterator

++ (increment) moves the iterator to the next element

begin() points the iterator at the first element

end() points the iterator at the last element

Generally speaking, we have the following sub-division of iterators and associated containers Sequence containers vector, deque

Random access iterators Sequence container list

Linear bidirectional iterator Associative containers set, multi-set, map,

multi-map Linear bidirectional iterator

No iterators supported for stack, queue, priority queue

Iterator operations Depends on iterator type A few examples

++p, p++,--p, p--(pre and post increment/decrement)

Applies to bidirectional and random access *p (de-referencing)

Applies to bidirectional and random access p==p1(test for equality)

Applies to bidirectional and random access

Example. vector

Enables efficient random access rather like an array but can re-size itself

Supports a random access iterator All STL algorithms can operate on a vector as

they all support random access A vector has a size (the actual number of

elements in the container) and a capacity (the number of elements that can be added before the vector resizes)

#include <vector>#include <vector>

int main()int main(){{

int array[6]={1,2,3,4,5,6};int array[6]={1,2,3,4,5,6};

vector<int> vec(array,array+6);vector<int> vec(array,array+6);

for (int *ptr=array; ptr!=(array+6); ptr++)for (int *ptr=array; ptr!=(array+6); ptr++)cout<<*ptr;cout<<*ptr;

vector<T>::iterator it;vector<T>::iterator it;for (it=vec.begin(); it!=vec.end(); it++)for (it=vec.begin(); it!=vec.end(); it++)

cout << *it;cout << *it;

// sort the vector// sort the vectorsort(vec.begin(),vec.end());sort(vec.begin(),vec.end());

}}

The previous program shows the similarity between array access using pointers and container access using an iterator Also de-referening an iterator (pointer) to access the

container (array) element Also the program shows how a sort() function is called

Iterators passed as arguments In general the STL is enormously powerful and should

always be used in preference to custom written container classes

Recommended