0% found this document useful (0 votes)
16 views138 pages

Bit2203 Introduction To Threads and Processes Exceptions and Exception Handling Operatoroverloading

Uploaded by

barasaeric
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views138 pages

Bit2203 Introduction To Threads and Processes Exceptions and Exception Handling Operatoroverloading

Uploaded by

barasaeric
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 138

lOMoARcPSD|19695326

BIT2203 - Introduction to threads and processes. Exceptions


and Exception handling. Operator
overloading.
Advance programming (Jomo Kenyatta University of Agriculture and Technology)

Scan to open on Studocu

Studocu is not sponsored or endorsed by any college or university


Downloaded by ERIC BARASA ([email protected])
lOMoARcPSD|19695326

JOMO KENYATTA UNIVERSITY


OF
AGRICULTURE & TECHNOLOGY

SCHOOL OF OPEN, DISTANCE &


eLEARNING
IN COLLABORATION WITH
SCHOOL OF COMPUTER SCIENCE AND
INFORMATION TECHNOLOGY

DEPARTMENT OF INFORMATION
TECHNOLOGY.

BIT 2203 ADVANCED PROGRAMMING

LAST REVISION ON May 19, 2014

Ochieng E. Owino
([email protected])

P.O. Box 62000, 00200


Nairobi, Kenya

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 ADVANCED PROGRAMMING


Course description
Introduction to threads and processes. Exceptions and Exception handling. Oper-
ator overloading. Function and class templates. Standard template libraries (STL).
Dynamic and static binding. Introduction to files; sequential access versus random
access, data files, text files. Writing data to text file, Reading data from text files,
functions for file streams : fseek, ftell. Database connectivity. Component-Based
Developments. Sockets. Remote method invocation (RMI).

Prerequisite:

• ICS 2104 Object Oriented Programming I

• ICS 2201 Object Oriented Programming II

Course aims
To enable the learner to understand advanced object-oriented programming con-
cepts.

Learning outcomes
Upon completion of the course the students should be able to:

1. Demonstrate advanced concepts of OOP.

2. Exhibit skills in advanced object-oriented programming.

Instruction methodology
Lectures, practical and tutorial sessions in Computer Laboratory, individual and
group assignments, exercises and project work

ii

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

Course Text Books


1. Tony Mullen (2007). Introducing Character Animation with Blender, ISBN-
13: 9780470102602, ISBN: 0470102608, Sybex.

2. Kit Laybourne, John Canemaker (1998) The Animation Book: A Complete


Guide to Animated Filmmaking, ISBN-13: 978-0517886021.

3. Kyle MacRae (2006). Desktop Publishing Manual: A practical introduction


to creating professional-looking documents and publications, ISBN-13: 978-
1844253173

Reference Textbooks:
1. Duggal, Vijay (2009). CADD primer : a general guide to computer aided
design and drafting, ISBN: 0-9629165-2-8.

2. Kyle MacRae (2008). Desktop Publishing Manual: A practical introduc-


tion to creating professional-looking documents and publications, ISBN 56-
7883958.

3. Christoph Schäfer and Gregory Pittman, (2009). Scribus: Open-Source Desk-


top Publishing, ISBN 5878-978-9859.

Course Journals
1. Acta Informatica ISSN 0001-5903.

2. Advances in Computational Mathematics ISSN 1019-7168.

3. Advances in data Analysis and Classification ISSN1 1862-5347.

4. Annals Of software Engineering ISSN 1022-7091.

Reference Journals
1. Journal of computer science and Technology ISSN 1000-9000.

2. Journal of Science and Technology ISSN 1860-4749.

3. Central European Journal Of Computer Science ISSN 1896-1533.

4. Cluster computing ISSN 1386-7857.

iii

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

Assessment information
The module will be assessed as follows;

• 30% Continuous Assessment (Tests 10%, Assignment 10%, Practical 10%).

• 70% End of Semester Examination..

iv

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

Contents

1 Introduction to Threads and Processes 1


1.1 Introduction to Process . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2 Process Creation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3 Process State . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.4 Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.5 Thread properties. . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.6 Kernel Threads and User Threads. . . . . . . . . . . . . . . . . . . 7
1.7 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

2 Exceptions in C++ 11
2.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.1.1 Exceptions and the throw and try..catch statements . . . . . 12
2.2 Exception specification . . . . . . . . . . . . . . . . . . . . . . . . 14
2.3 Standard exceptions . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.4 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

3 Standard Template Library 19


3.1 Introduction to Process . . . . . . . . . . . . . . . . . . . . . . . . 20
3.2 Containers: Introduction . . . . . . . . . . . . . . . . . . . . . . . 20
3.2.1 Sequence containers . . . . . . . . . . . . . . . . . . . . . 21
3.2.2 Associative containers . . . . . . . . . . . . . . . . . . . . 21
3.2.3 Container adapters . . . . . . . . . . . . . . . . . . . . . . 21
3.2.4 Specialized containers . . . . . . . . . . . . . . . . . . . . 22
3.3 Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
3.3.1 Iterators: an alternative way of accessing the elements . . . . 26
3.4 STL LIST: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.5 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

CONTENTS CONTENTS

4 Introduction to C++ Templates 31


4.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.2 Defining Templates . . . . . . . . . . . . . . . . . . . . . . . . . . 33
4.2.1 Template Parameters . . . . . . . . . . . . . . . . . . . . . 33
4.2.2 Template Type Parameters . . . . . . . . . . . . . . . . . . 34
4.2.3 Template Non-Type Parameters . . . . . . . . . . . . . . . 35
4.2.4 Template Template Parameters . . . . . . . . . . . . . . . . 36
4.2.5 Default Template Parameters . . . . . . . . . . . . . . . . . 37
4.2.6 Dependent Names . . . . . . . . . . . . . . . . . . . . . . . 37
4.3 Using Templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
4.4 Template Requirements and Concepts . . . . . . . . . . . . . . . . 42
4.4.1 Template Specialization and Overloading . . . . . . . . . . 44
4.4.2 Explicit Specialization . . . . . . . . . . . . . . . . . . . . 45
4.4.3 Partial Specialization . . . . . . . . . . . . . . . . . . . . . 46
4.4.4 Function Template Overloading . . . . . . . . . . . . . . . 48
4.5 Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50

5 Introduction notes on files programming 53


5.1 Basics in file programming . . . . . . . . . . . . . . . . . . . . . . 53
5.1.1 Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
5.1.2 Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
5.2 Writing data to file . . . . . . . . . . . . . . . . . . . . . . . . . . 56
5.3 Reading data from a file . . . . . . . . . . . . . . . . . . . . . . . . 58
5.4 Reading Text Files(revisited) . . . . . . . . . . . . . . . . . . . . . 61
5.4.1 Reading numbers . . . . . . . . . . . . . . . . . . . . . . . 63
5.4.2 Reading Lines . . . . . . . . . . . . . . . . . . . . . . . . . 64
5.4.3 Reading Characters . . . . . . . . . . . . . . . . . . . . . . 65
5.5 Summary on I/O streams . . . . . . . . . . . . . . . . . . . . . . . 66

6 Early binding and late binding 75


6.1 Introduction to Binding . . . . . . . . . . . . . . . . . . . . . . . . 75
6.2 Early binding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
6.3 Late Binding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
6.4 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80

vi

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

CONTENTS CONTENTS

7 C++ Programming Operator Overloading 82


7.1 Introduction to operator loading . . . . . . . . . . . . . . . . . . . 83
7.2 Why Operator overloading is used in C++ programming? . . . . . . 83
7.3 How to overload operators in C++ programming . . . . . . . . . . . 83
7.4 Considerations while using Operator overloading in C++ language . 84
7.5 Increment ++ and Decrement – Operator Overloading in C++ Pro-
gramming. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
7.6 Operator Overloading of Postfix Operator . . . . . . . . . . . . . . 88
7.7 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92

8 Component-Based Developments 94
8.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
8.2 The Software Crisis. . . . . . . . . . . . . . . . . . . . . . . . . . . 96
8.3 General design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
8.3.1 Coupling & Cohesion . . . . . . . . . . . . . . . . . . . . 98
8.4 What is a Component . . . . . . . . . . . . . . . . . . . . . . . . . 99
8.4.1 Component Model . . . . . . . . . . . . . . . . . . . . . . 99
8.4.2 Component Framework . . . . . . . . . . . . . . . . . . . . 99
8.5 Life Cycle of Component Based Software Engineering . . . . . . . 100
8.5.1 Requirements Analysis Phase . . . . . . . . . . . . . . . . . 100
8.5.2 Architecture Selection Phase . . . . . . . . . . . . . . . . . 101
8.5.3 Component Identification Phase . . . . . . . . . . . . . . . 101
8.5.4 System Integration Phase . . . . . . . . . . . . . . . . . . . 101
8.5.5 Testing Phase . . . . . . . . . . . . . . . . . . . . . . . . . 102
8.5.6 Maintenance Phase . . . . . . . . . . . . . . . . . . . . . . 102
8.6 Current Component Technologies . . . . . . . . . . . . . . . . . . 103
8.7 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103

9 Introduction to Sockets Programming 105


9.1 Introduction to Sockets . . . . . . . . . . . . . . . . . . . . . . . . 106
9.2 Socket characteristics . . . . . . . . . . . . . . . . . . . . . . . . . 106
9.3 What are Threads, Ports, and how are related to Sockets? . . . . . . 107
9.4 Working with Winsock . . . . . . . . . . . . . . . . . . . . . . . . 107
9.5 Initializing a Socket . . . . . . . . . . . . . . . . . . . . . . . . . . 108
9.5.1 Connecting to a Remote Host (Acting as the Client) . . . . . 109

vii

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

CONTENTS CONTENTS

9.6 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113

10 Remove Method Invocation in C++ 115


10.1 Introduction to Remote Method Invocation. . . . . . . . . . . . . . 116
10.1.1 A Simple Example . . . . . . . . . . . . . . . . . . . . . . 116
10.2 Basic Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
10.3 Implementing RMI for C++ Objects . . . . . . . . . . . . . . . . . 121
10.3.1 Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
10.4 Extending the Interface . . . . . . . . . . . . . . . . . . . . . . . . 123
10.5 Adding User defined Types . . . . . . . . . . . . . . . . . . . . . . 125
10.6 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
Solutions to Exercises . . . . . . . . . . . . . . . . . . . . . . . . . 129

viii

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

LESSON 1
Introduction to Threads and Processes

Learning outcomes
Upon completing this topic, you should be able to:

• Understand threads and Processes

• Create Threads and Processes.

• Differentiate threads and processes.

• Write threads and processes in C++.

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

1.1. Introduction to Process


Process :- "An execution stream in the context of a particular process state."

• Execution stream: a sequence of instructions (only one thing happens at a


time).

• Process state: everything that can affect, or be affected by, the process: code,
data, call stack, open files, network connections, etc.

Uniprogramming system: only supports a single process. Simplifies some parts of


OS, but many other things are hard to do.

• Some early personal computer operating systems were uniprogramming (e.g.


MS-DOS), but these systems are almost unheard of today.

• This is not called "uniprocessing": that refers to a system with only one pro-
cessor.

Virtually all modern operating systems are multiprogramming systems: multiple


processes can exist simultaneously and share the machine.

Dispatching
OS uses a process control block to keep track of each process:

• Execution state for each thread (saved registers, etc.).

• Scheduling information.

• Memory used by this process.

• Information about open files.

• Accounting and other miscellaneous information

The dispatcher is inner-most portion of the OS that runs processes:

• Run a thread for a while.

• Save its state and load state of another thread.

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

How dispatcher decide which process to run next.


• Plan 0: search process table from front, run first ready thread.

• Plan 1: Link together the ready threads into a queue. Dispatcher grabs first
thread from the queue. When threads become ready, insert at back of queue.

• Plan 2: give each thread a priority, organize the queue according to priority.
Or, perhaps have multiple queues, one for each priority class.

CPU can only be doing one thing at a time: if a thread is executing, dispatcher isn’t:
OS has lost control. How does OS regain control of processor?
Traps (events occurring in current thread that cause a change of control into the
operating system):

• System call.

• Error (illegal instruction, addressing violation, etc.).

• Page fault.

Interrupts (events occurring outside the current thread that cause a state switch into
the operating system)):

• Character typed at keyboard.

• Completion of disk operation (controller is ready for more work).

• Timer: to make sure OS eventually gets control.

When thread isn’t running, its state must be saved in process control block. What
gets saved? Everything that next thread could damage:

• Program counter.

• Processor status word (condition codes, etc.).

• Registers.

• Floating-point registers.

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

1.2. Process Creation


Creating a process from scratch:

• Load code and data into memory.

• Create and initialize process control block.

• Create first thread with call stack.

• Provide initial values for "saved state" for the thread.

• Make process known to dispatcher; dispatcher "resumes" to beginning of pro-


cess.

Process creation in UNIX:

• Fork makes copy of current process, with one thread.

• Exec replaces memory with code and data from a given executable file.

• Doesn’t return ("returns" into new process).

• Waitpid waits for a given process to exit.

Example:
int pid = fork();
if (pid == 0)
{ /* Child process */
exec("foo");
}
else{ /* Parent process */
waitpid(pid, &status, options);
}
Process creation in Windows:
CreateProcess combines fork and exec
BOOL CreateProcess(
LPCTSTR lpApplicationName,
LPTSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
PVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation );

1.3. Process State


Processes may be in one of 5 states, as shown in Figure 1 below.

• New - The process is in the stage of being created.

• Ready - The process has all the resources available that it needs to run, but
the CPU is not currently working on this process’s instructions.

• Running - The CPU is working on this process’s instructions.

• Waiting - The process cannot run at the moment, because it is waiting for
some resource to become available or for some event to occur. For example
the process may be waiting for keyboard input, disk access request, inter-
process messages, a timer to go off, or a child process to finish.

• Terminated - The process has completed.

Figure 1: Process States

1.4. Threads
A thread is an independent flow of control that operates within the same address
space as other independent flows of controls within a process.

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

Traditionally, thread and process characteristics are grouped into a single entity
called a process. In other operating systems like linux, threads are sometimes called
lightweight processes, Most modern operating systems also support threads: multi-
ple execution streams within a single process.

• Threads share process state such as memory, open files, etc.

• Each thread has a separate stack for procedure calls (in shared memory).

• Thread is unit of sequential execution.

Why support threads?

• Concurrent execution on multiprocessors.

• Manage I/O more efficiently: some threads wait for I/O while others compute.

• Most common usage for threads: large server applications

1.5. Thread properties.


A thread is the schedulable entity, It has only those properties that are required to
ensure its independent control of flow. These include the following properties:

• Stack.

• Scheduling properties (such as policy or priority).

• Set of pending and blocked signals.

• Some thread-specific data.

An example of thread-specific data is the errno error indicator. In multithreaded


systems, errno is no longer a global variable, but usually a subroutine returning
a thread-specific errno value. Some other systems may provide other implemen-
tations of errno. Threads within a process must not be considered as a group of
processes. All threads share the same address space.

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

1.6. Kernel Threads and User Threads.


A kernel thread is the schedulable entity, which means that the system scheduler
handles kernel threads. These threads, known by the system scheduler, are strongly
implementation-dependent. To facilitate the writing of portable programs, libraries
provide user threads. A kernel thread is a kernel entity, like processes and interrupt
handlers; it is the entity handled by the system scheduler. A kernel thread runs
within a process, but can be referenced by any other thread in the system. The
programmer has no direct control over these threads, unless you are writing kernel
extensions or device drivers A user thread is an entity used by programmers to
handle multiple flows of controls within a program. The API for handling user
threads is provided by the threads library. A user thread only exists within a process;
a user thread in process A cannot reference a user thread in process B. The library
uses a proprietary interface to handle kernel threads for executing user threads. On
other systems, user threads are simply called threads, and lightweight process refers
to kernel threads.
Examples of a code to a create a process
#include<sys/types.h>
#include<stdio.h>
#include<unistd.h>
int main() {
Pid_t pid;
/* fork child process */
pid=fork();
if(pid<0)
{
/*error occurred */
fprint(stderr,”fork failed”);
exit(-1);
}
Else if(pid==0)
{ //child process
execlp(“/bin/ls”,”ls”,NULL);
} Else { //parent process //The parent will wait the child process to complete
Wait(NULL);

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

Printf(“child complete”);
exit(0);
}
}
C program using a fork for separate processes.
Creating a separate process using the UNIX fork( ) system call.

Figure 2: Process creation.


Below is more complicated process for Windows, which must provide all of the
parameter information for the new process as part of the forking process.
#include<stdio.h>
#include<windows.h>
int main(VOID)
{
STARTUPINFO si; PROCESS_INFORMATION p;
//allocate memory ZeroMemory(&si,sizeof(si));
si.cb=sizeof(si);
ZeroMemory(&p,sizeof(p)); //create a child process
if(!CreateProcess(NULL,// use command line
"C;\\windows\\system32\\mspaint.exe",//comman line NULL,
//do not inherite process handle
NULL,//do not inherite thread handle
FALSE,//disable the handle inheritance 0,//no creation flags.
NULL,//use parents enviroment block
NULL,//use parents existing directory &si,&p))
{
fprintf(stderr,"Create process failed");
return -1;
} // parent will wait for the child to complete
WaitForSingleObject(p.hProcess,INFINITE);
printf("Child Completed"); //close handles

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

CloseHandle(p.hProcess);
CloseHandle(p.hThread);
}

1.7. Summary
Process :- "An execution stream in the context of a particular process state."

• Stack.

• Scheduling properties (such as policy or priority).

• Set of pending and blocked signals.

• Some thread-specific data.

A kernel thread is the schedulable entity, which means that the system scheduler
handles kernel threads.

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

Revision Questions

Example . Name three properties of a process


Solution:
Stack.
Scheduling properties (such as policy or priority).
Set of pending and blocked signals.
Some thread-specific data. 

E XERCISE 1.  Differentiate between Kernel and user threads.


E XERCISE 2.  Differentiate between interrupts and traps.
E XERCISE 3.  Name and explain three states of a process.
E XERCISE 4.  Discuss how dispatcher works.

Problem. Using a diagram shows how CPU switches from process to process.

10

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

LESSON 2
Exceptions in C++

Learning outcomes
By the end of this topic you should be able to;

• Define and understand exceptions.

• Differentiate between try and catch blocks in of the exceptions

• Understand the standard exceptions in C++.

• Write a program that uses Exceptions in C++

11

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

2.1. Introduction
2.1.1. Exceptions and the throw and try..catch statements
Exceptions allow passing information about some exception condition (usually an
error) by means of the throw statement to the catch clause that encloses it or any of
the calls on the call stack. The calls look identical, and the error processing code is
in the function that wants to catch it.
Exceptions provide a way to react to exceptional circumstances (like runtime errors)
in programs by transferring control to special functions called handlers.
To catch exceptions, a portion of code is placed under exception inspection. This is
done by enclosing that portion of code in a try-block. When an exceptional circum-
stance arises within that block, an exception is thrown that transfers the control to
the exception handler. If no exception is thrown, the code continues normally and
all handlers are ignored.
An exception is thrown by using the throw keyword from inside the try block.
Exception handlers are declared with the keyword catch, which must be placed
immediately after the try block:
// exceptions
#include <iostream>
using namespace std;
int main ()
{
try
{
throw 20;
}
catch (int e)
{
cout << "An exception occurred. Exception Nr. " << e << ’\n’;
}
return 0;
}
The code under exception handling is enclosed in a try block. In this example this
code simply throws an exception:

12

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

throw 20;
A throw expression accepts one parameter (in this case the integer value 20), which
is passed as an argument to the exception handler.
The exception handler is declared with the catch keyword immediately after the
closing brace of the try block. The syntax for catch is similar to a regular function
with one parameter. The type of this parameter is very important, since the type of
the argument passed by the throw expression is checked against it, and only in the
case they match, the exception is caught by that handler.
Multiple handlers (i.e., catch expressions) can be chained; each one with a different
parameter type. Only the handler whose argument type matches the type of the
exception specified in the throw statement is executed.
If an ellipsis (...) is used as the parameter of catch, that handler will catch any
exception no matter what the type of the exception thrown. This can be used as a
default handler that catches all exceptions not caught by other handlers:
try
{
// code here
}
catch (int param)
{
cout << "int exception";
}
catch (char param)
{
cout << "char exception";
}
catch (...)
{
cout << "default exception";
}
In this case, the last handler would catch any exception thrown of a type that is
neither int nor char.
After an exception has been handled the program, execution resumes after the try-
catch block, not after the throw statement!.

13

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

It is also possible to nest try-catch blocks within more external try blocks.
In these cases, we have the possibility that an internal catch block forwards the
exception to its external level. This is done with the expression throw; with no
arguments.
For example:
try
{
try
{ // code here
}
catch (int n)
{
throw;
}
}
catch (...)
{
cout << "Exception occurred";
}

2.2. Exception specification


Older code may contain dynamic exception specifications. They are now depre-
cated in C++, but still supported. A dynamic exception specification follows the
declaration of a function, appending a throw specifier to it. For example: double
myfunction (char param) throw (int);
This declares a function called myfunction, which takes one argument of type char
and returns a value of type double. If this function throws an exception of some type
other than int, the function calls std::unexpected instead of looking for a handler or
calling std::terminate.
If this throw specifier is left empty with no type, this means that std::unexpected
is called for any exception.
Functions with no throw specifier (regular functions) never call std::unexpected,
but follow the normal path of looking for their exception handler.
int myfunction (int param) throw(); // all exceptions call unexpected

14

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

int myfunction (int param); // normal exception handling

2.3. Standard exceptions


The C++ library defines a number of common exceptions. Use #include <stdex-
cept> using namespace std; // Or prefix names with std:: to get the following classes
defined. These are arranged in a class hierarchy shown by the indentation below.
Exceptions

• Logic_error

– domain_error
– invalid_argument
– length_error
– out_of_range

• Runtime_error

– Range_error
– overflow_error

Standard exception constructor To create an exception and throw it, call the con-
structor with a c-string parameter. throw out_of_range("Subscript less than zero");
Catching a standard exception You can catch an exception of a specific type, or any
of its subclasses, by specifying the class name as the type of the parameter in the
catch clause.
Call the what method to get the error string from a standard exception.
vector<int> v; // using standard vector class . . .
try { . . .
x = v.at(-2); // this throws out_of_range exception. . . .
} catch (out_of_range e)
{
cerr << e.what() << endl; // print error
exit(1); // stop program
}

15

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

The C++ Standard library provides a base class specifically designed to declare ob-
jects to be thrown as exceptions. It is called std::exception and is defined in the <ex-
ception> header. This class has a virtual member function called what that returns
a null-terminated character sequence (of type char *) and that can be overwritten in
derived classes to contain some sort of description of the exception.
// using standard exceptions
#include <iostream>
#include <exception>
using namespace std;
class myexception: public exception
{
virtual const char* what()
const throw()
{
return "My exception happened";
}
}
myex;
int main ()
{
try
{
throw myex;
}
catch (exception& e)
{
cout << e.what() << ’\n’;
}
return 0;
}
We have placed a handler that catches exception objects by reference (notice the
ampersand & after the type), therefore this catches also classes derived from excep-
tion, like our myex object of type myexception.

16

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

All exceptions thrown by components of the C++ Standard library throw exceptions
derived from this exception class. These are:
The following are exceptions with their descriptions.

• bad_alloc thrown by new on allocation failure

• bad_cast thrown by dynamic_cast when it fails in a dynamic cast.

• bad_exception thrown by certain dynamic exception specifiers.

• bad_typeid thrown by typeid .

• bad_function_call thrown by empty function objects.

• bad_weak_ptr thrown by shared_ptr when passed a bad weak_ptr

Also deriving from exception, header <exception> defines two generic exception
types that can be inherited by custom exceptions to report errors: exception de-
scription logic_error error related to the internal logic of the program runtime_error
error detected during runtime
A typical example where standard exceptions need to be checked for is on memory
allocation: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // bad_alloc standard exception
#include <iostream>
#include <exception>
using namespace std;
int main ()
{
try
{
int* myarray= new int[1000];
}
catch (exception& e)
{
cout << "Standard exception: " << e.what() << endl;
}
return 0;
}

17

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

The exception that may be caught by the exception handler in this example is a
bad_alloc. Because bad_alloc is derived from the standard base class exception, it
can be caught (capturing by reference, captures all related classes).

2.4. Summary
Exceptions allow passing information about some exception condition (usually an
error) by means of the throw statement to the catch clause that encloses it or any of
the calls on the call stack. The calls look identical, and the error processing code is
in the function that wants to catch it.
Exceptions provide a way to react to exceptional circumstances (like runtime errors)
in programs by transferring control to special functions called handlers.

Revision Questions

Example . Explain the concept of exception


Solution:
Exceptions allow passing information about some exception condition (usually an
error) by means of the throw statement to the catch clause that encloses it or any of
the calls on the call stack. The calls look identical, and the error processing code is
in the function that wants to catch it. 

E XERCISE 5.  Differentiate between try and catch blocks.


E XERCISE 6.  Write a program to explain more about exceptions.
E XERCISE 7.  Discuss the exception specifications.
E XERCISE 8.  Name and explain atleast three more exception types

Problem. Discuss the standard exceptions..

18

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

LESSON 3
Standard Template Library

Learning outcomes
Upon completing this topic, you should be able to:

• Understand Standard Template Library.

• Understand Containers,Iterators and Algorithms

• Write program codes for different STL.

• Understand the importance of STL’s.

19

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

3.1. Introduction to Process


The Standard Library is a fundamental part of the C++ Standard. It provides C++
programmers with a comprehensive set of efficiently implemented tools and facil-
ities that can be used for most types of applications. The STL (Standard Tem-
plate Library) provides a number of predefined containers (data structures), most of
which are generalize as templates to hold any type element.
Stl is based on the cooperation of different well-structured components,keys of
which are containers,iterators and algorithms.

• Container: Containers are used to manage collections of objects of a ceratin


kind.Every kind of container has its own advantages and disadvantages,so
having different container types reflects different requirement for collections
in programs.

• Iterators:are used to step through the elements of collections of objects.these


collections may be containers or subsets of containers.the major advantage of
iterators is that they offer small but common interface for the any arbitrary
container type.

• Algorithms:These are used to process the elements of the collections.ie they


can search,sort,modify,simply use the element for different purposes.

3.2. Containers: Introduction


Containers are used to manage collections of objects of a ceratin kind.Every kind
of container has its own advantages and disadvantages,so having different container
types reflects different requirement for collections in programs. Containers are ob-
jects that conceptually contain other objects. They use certain basic properties of
the objects (ability to copy, etc.) but otherwise do not depend on the type of object
they contain. The most commonly used are string and vector.
Containers are divided into two main:

• Sequence: are ordered collections in which every element has a certain po-
sition.This position depends on the time and place of the insertion,but it
is independent on the value of the element.These include classes like vec-
tor,deque,and a list.

20

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

• Associative:are sorted collections in which the actual position of the ele-


ment depends on its value due to a certain sorting criterion.the classes in-
clude:set,multiset,map and multimap.

3.2.1. Sequence containers


These containers hold sequences of data elements.

• Vector: provides a dynamic array structure with fast random access to any
element. Inserting and deleting elements at the end is fast. Can do subscript
bounds checking.

• Deque: also provides a dynamic array structure with random access and adds
fast insertion and deletion of elements at front as well as from the back. Very
slightly slower than vector because of an extra level of indirection.

• List: is usually implemented as a doubly linked list. There is no random


access to the elements. Insertion and deletion anywhere is fast.

3.2.2. Associative containers


Associative containers contain key/value pairs, providing access to each value using
a key. The elements are sorted by the key. Usually implemented as a balanced
binary tree.

• Map: provides access to elements using any type of key. This is a general-
ization of the idea of accessing a vector with an integer subscript.

• Multimap: is the same as map, but allows a key to map into more than one
element.

3.2.3. Container adapters


These are based on other containers, and are used only to enforce access rules.
Because there are special access restrictions, they have no iterators.

• Stack: allows only LIFO (Last In, First Out) access.

• Queue: allows only FIFO (First In, First Out) access.

• Priority queue: always returns the element with the highest priority.

21

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

3.2.4. Specialized containers


The following containers are specialized in some ways: specific data type, special
utility routines, limited, but fast, implementations.

• String: holds character strings - similar to vector<char>, but with many use-
ful utility functions.

• Bitset: is a storage-efficient data structure for bits. By defining the bit opera-
tions, it effectively implements set operations.

• Valarray: is an especially efficient implementation of arrays, but it doesn’t


have all the standard container behavior.

3.3. Iterators
Iterators are used to access members of the container classes, and can be used in a
similar manner to pointers. For example, one might use an iterator to step through
the elements of a vector. There are several different types of iterators:

• Input_iterator-Read values with forward movement. These can be incre-


mented, compared, and dereferenced.

• Output_iterator- Write values with forward movement. These can be incre-


mented and dereferenced.

• Forward_iterator-ead or write values with forward movement. These com-


bine the functionality of input and output iterators with the ability to store the
iterators value.

• Bidirectional_iterator-Read and write values with forward and backward


movement. These are like the forward iterators, but you can increment and
decrement them.

• Random_iterator-Read and write values with random access. These are the
most powerful iterators, combining the functionality of bidirectional iterators
with the ability to do pointer arithmetic and pointer comparisons.

• Reverse_iterator Either a random iterator or a bidirectional iterator that moves


in reverse direction.

22

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

Each of the container classes is associated with a type of iterator, and each of the
STL algorithms uses a certain type of iterator. For example, vectors are associated
with random-access iterators, which means that they can use algorithms that require
random access. Since random-access iterators encompass all of the characteristics
of the other iterators, vectors can use algorithms designed for other iterators as well.
The following code creates and uses an iterator with a vector:
vector<int> the_vector;
vector<int>::iterator the_iterator;
for( int i=0; i < 10; i++ ) the_vector.push_back(i);
int total = 0;
the_iterator = the_vector.begin();
while( the_iterator != the_vector.end() )
{
total += *the_iterator; the_iterator++;
}
cout << "Total=" << total << endl;
Notice that you can access the elements of the container by dereferencing the iter-
ator. Vectors (Sequence container): Arrays are a programming tool that provide a
mechanism to store a group of values under a single name. The values can be any
available data type (e.g., int, double, string, etc.). In C++, talk about vectors, rather
than arrays.
Vectors are declared with the following syntax:
vector<type> variable_name (number_of_elements);
Type refers to the data type of the elements of the array; variable_name is the name
that we assign to the vector, and the optional number_of_elements may be provided
to indicate how many elements the vector will contain.
Examples of vector declarations are the following:
vector<int> values (5); // declares a vector of 5 integers
vector<double> marks (20); // declares a vector of 20 doubles.
When we use vectors in our programs, we must provide, at the top of the file,
the line: #include <vector> After a vector has been declared specifying a certain
number of elements, we can refer to individual elements in the vector using square
brackets to provide a subscript or an index. In the following example, the program
asks the user for the marks for a group of 20 students and stores them in a vector:

23

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<double> student_marks (20);
for (int i = 0; i < 20; i++)
{
cout << "Enter marks for student #" << i+1 << ": ";
cin >> student_marks[i];
}
return 0;
}
The first statement (right after main) declares a vector called student_marks with
capacity to hold 20 values of type double. These values can be accessed individually
as student_marks[0] to student_marks[19]. The for loop has the counter i go from
0 to 19, allowing access to each individual element in a sequential manner, starting
at 0 and going through each value from 0 to 19, inclusively.
Vectors have one important advantage with respect to arrays in C, C++ and in other
languages: vectors can be resized during the execution of the program to accom-
modate extra elements as needed. Many other programming languages suffer the
limitation of fixed-size arrays; that is, once the arrays are declared with a size, they
can not be resized later in the program. In the example above, if we do know in ad-
vance that there are 20 students. Remember we could also ask the user how many
students are there, and resize the vector accordingly.
This is as shown in the example below:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<double> student_marks; // no size specified: vector contains
// zero elements
int num_students;

24

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

cout << "Number of students in this group: ";


cin >> num_students;
student_marks.resize (num_students);
for ( int i = 0; i < num_students; i++)
{
cout << "Enter marks for student #" << i+1 << ": ";
cin >> student_marks[i];
}
return 0;
}
Notice that the valid subscripts for a vector with num_students elements are 0 to
num_students-1. For that reason, the for loop goes from 0, while i is less than
num_elements. It’s always a better idea to control for loops using the size() method
of vector. That way, we make sure that we loop only through the right subscript
values, and we avoid the risk of accidentally exceeding the limits of the vector:
for (int i = 0; i < student_marks.size(); i++)
The difference in this case seems insignificant, and it almost sounds unnecessary to
use the size() method; but again, it’s always a good idea to stick to good program-
ming practices that may be very convenient in larger or more complex programs. In
some situations, we can’t determine the number of elements before reading them.
That is, we may have to read numbers and store them in an array to then determine
when to stop reading values. In such situations, the trick of resizing the vector is
not an option.
Vectors provide a convenient way of handling this type of situation.
We can use the push_back() method to append one element at the end of the array.
The operation includes resizing to one more element to accommodate for the extra
element, and storing the given value at the end of the array. The example below
shows how to use the push_back() method to accept numbers from the user and
store them in a vector, until the user indicates that there are no more numbers. After
all the numbers were entered, we use a for loop to print them in the order that they
were entered (this is just for illustrations purpose – it’s not particularly useful to do
that!):
#include <iostream>
#include <vector>

25

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

using namespace std;


int main()
{
vector<double> student_marks;
int number;
char answer;
cout << "Do you want to enter numbers (y/n)? ";
cin >> answer;
while (answer == ’y’)
{
cout << "Enter value: ";
cin >> number; // Now that we have the number from the user, // append it at the
end of the vector student_marks.push_back(number);
cout << "Do you want to enter more numbers (y/n)? ";
cin >> answer;
}
// Now print all the values; notice that we didn’t need to // count how many elements
were entered: we can always use // the size() method to ask student_marks how
many are there!
for (int i = 0; i < student_marks.size(); i++)
{
cout << "Student #" << i+1 << ’\t’ << student_marks[i];
} // ’\t’ is the code for the TAB character
return 0;
}

3.3.1. Iterators: an alternative way of accessing the elements


Iterators provide an arguably more flexible way of accessing elements in a vector.
They allow you to refer directly to the elements of the vector and iterate over the
entire vector.
To work with iterators, we first declare a variable of type iterator. When declaring
the iterator, we have to specify that it is an iterator for a vector of the given type, as
shown in the example below:
vector<int>::iterator i;

26

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

This statement declares an iterator to iterate over the elements of a vector of ints.
The iterator variable (in the above example, i) allows us to access a particular ele-
ment, and to move to the next element (those two operations are clearly necessary
if we want to iterator over all the elements of the vector).
To access the element "pointed to" by the iterator, we place a * operator in front.
To advance to the next element, we use the ++ operator (either pre-increment or
post-increment, although with iterators, it is slightly more efficient to use the pre-
increment form).
So, the following fragment of code prints an element and moves the itertator to the
next element:
cout << *i << endl; ++i;
We need to do this in a loop, which means that we need to make our iterator start at
the beginning of our vector, and loop while it still is within the vector’s elements.
To do this, we use the .begin() and .end() methods of vector.
These methods give us iterators positioned at the beginning and at the end of the
vector (more specifically, .end() will give us an iterator positioned at one-past-the-
last element, such that we can use it to control the loop).
The following fragment of code illustrates the use of iterators to print all the ele-
ments of a vector: // values has been declared as:
vector<int> values;
for (vector<int>::iterator i = values.begin(); i != values.end(); ++i)
{
cout << *i << endl;
}
Notice that, because values.end()is an iterator placed at one-past-the-last element,
when i is equal to that value, then we exit the loop, since that means that we are now
outside the range of the vector’s elements. If we have a vector of strings and want
to print the elements (the strings) and their lengths, we could do the following: //
names has been declared as: vector<string> names;
for (vector<string>::iterator i = names.begin(); i != names.end(); ++i)
{
cout << "Name: " << *i << "\tLength: " << (*i).length() << endl;
}
Instead of writing (*i).length() (we need the parenthesis, because the dot operator

27

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

has higher precedence than the unary * operator), we could simply write i->length(),
as shown in the fragment below, which is exactly equivalent to the above: for (vec-
tor<string>::iterator i = names.begin(); i != names.end(); ++i) { cout << "Name: "
<< *i << "\tLength: " << i->length() << endl; }

3.4. STL LIST:


LIST: Linked list of variables, struct or objects. Insert/remove anywhere. Two
examples are given:

1. The first STL example is for data type int.

2. The second for a list of class instances. They are used to show a simple
example and a more complex real world application.

Lets start with a simple example of a program using STL for a linked list: // Stan-
dard Template Library example
#include <iostream>
#include <list>
using namespace std;
// Simple example uses type int
main()
{
list<int> L;
L.push_back(0); // Insert a new element at the end
L.push_front(0); // Insert a new element at the beginning
L.insert(++L.begin(),2); // Insert "2" before position of first argument // (Place be-
fore second argument)
L.push_back(5);
L.push_back(6);
list<int>::iterator i;
for(i=L.begin(); i != L.end(); ++i)
cout << *i << " ";
cout << endl;
return 0;
}

28

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

Output:
02056

3.5. Summary
Stl is based on the cooperation of different well-structured components,keys of
which are containers,iterators and algorithms.

• Container: Containers are used to manage collections of objects of a ceratin


kind.Every kind of container has its own advantages and disadvantages,so
having different container types reflects different requirement for collections
in programs.

• Iterators:are used to step through the elements of collections of objects.these


collections may be containers or subsets of containers.the major advantage of
iterators is that they offer small but common interface for the any arbitrary
container type.

• Algorithms:These are used to process the elements of the collections.ie they


can search,sort,modify,simply use the element for different purposes.

29

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

Revision Questions

Example . Explain the term a container in C++ STL


Solution:
Containers are used to manage collections of objects of a ceratin kind.Every kind
of container has its own advantages and disadvantages,so having different container
types reflects different requirement for collections in programs. . 

E XERCISE 9.  Write a program that uses a vector to store the names of 20 stu-
dents .
E XERCISE 10.  Give atleast two types of STL components.
E XERCISE 11.  Write a program that can be used to store 30 numbers in a linked
list..
E XERCISE 12.  Differentiate between a vector and a list in C++ langauge

Problem. Normally in a program that uses STL components,it uses the namespace
and the template class of a particular class of the STL component.write a program
code to use a namespace include a STL component class template of your choice.
Write a program that reads words from the standard input and when the input is
reached prints out each word once, with a count of the number of times it occurred
in the input. You will need a map from strings to integers to keep track of the
number of occurrences of each word. Because there is as yet no easy way to get all
the words in a map, you will also need to maintain a vector or list of all the words
seen (but only one of each).

30

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

LESSON 4
Introduction to C++ Templates

Learning outcomes
Upon completing this topic, you should be able to:

• Understand C++ Templates

• Write a C++ program that uses templates

• Differentiate between class templates and function templates

• Understand the benefits of using C++ templates.

4.1. Introduction
Introduction C++ templates are a powerful mechanism for code reuse, as they en-
able the programmer to write code that behaves the same for data of any type.
Suppose you write a function printData:
void printData(int value)
{
std::cout<<"The value is "<<value<<std::endl;
}
If you later decide you also want to print double values,
or std::string values, then you have to overload the function:
void printData(double value)
{
std::cout<<"The value is "<<value<<std::endl;
}
void printData(std::string value)
{
std::cout<<"The value is "<<value<<std::endl;
}
The actual code written for the function is identical in each case; it is just the type
of the variable value that changes, yet we have to duplicate the function for each
distinct type. This is where templates come in – they enable the user to write the
function once for any type of the variable value.

31

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

template<typename T>
void printData(T value)
{
std::cout<<"The value is "<<value<<std::endl;
}
That’s all there is to it1 - we can now use printData for any data that can be written
to a std::ostream.
Here, the template<typename T> part tells the compiler that what follows is a tem-
plate, and that T is a template parameter that identifies a type.
Then, anywhere in the function where T appears, it is replaced with whatever type
the function is instantiated for - e.g.:
If we were really writing a generic function like this, we would probably pass the
parameter as a const reference,
rather than as a value parameter to avoid copying large objects - the same applies to
void printData(std::string value) above,
it would be more usual to write void printData(const std::string& value)
int i=3;
double d=4.75;
std::string s("hello");
bool b=false;
printData(i); // T is int
printData(d);// T is double
printData(s); // T is std::string
printData(b);// T is bool
It is possible to write class templates as well as function templates like printData.
A common example is std::vector - you can specify a vector of integers, or of
strings, or of some user-defined class, simply by specifying the template param-
eter:
class MyClass{};
std::vector<int> vi; // contains ints
std::vector<double> vd; // contains doubles
std::vector<std::string> vs; // contains std::strings
std::vector<MyClass> vmc; // contains MyClass objects

32

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

4.2. Defining Templates


A Template Definition starts with the keyword template, followed by a list of Tem-
plate Parameters What follows is then either a class definition, or a function defi-
nition, defining a class template or a function template respectively. The template
parameters introduce names into the scope of the definition, which can be types,
values or templates. These names can be used just like any other name of the same
kind. Then, when the template is instantiated, real types, values or templates are
substituted in place of these names, and the code compiled.

4.2.1. Template Parameters


Templates can have one or more template parameters, which can be

• Type parameters (such as those in the introduction),

• Non-Type parameters (e.g. an integer), or

• Template parameters.

Two template instantiations refer to the same template if their parameters are all the
same, irrespective of any typedefs that may apply.
Therefore vec1, vec2 and vec3 in the following example are all the same type.
typedef std::string MyString;
typedef std::vector<std::string> T1;
typedef std::vector<MyString> T2;
T1 vec1;
T2 vec2;
std::vector<std::string> vec3;
Multiple parameters may be specified, separated by commas in the template param-
eter list:
template<typename T1,typename T2>
class MyClass{ };
MyClass is thus a class template with two template type parameters, T1 and T2
Every time a template is referenced with distinct template arguments,
then the template is instantiated with the arguments substituted as explained in the
following sections.

33

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

If the resultant code is not valid, then a compilation error will occur.

4.2.2. Template Type Parameters


Template Type Parameters are template parameters that refer to a type; they are the
most common form of template parameters. The template parameter for printData
in the introduction is an example of a template type parameter.
The syntax is simple:
typename name or
class name
Both alternatives are identical in meaning, and the choice is merely a matter of
style. name is any valid C++ symbol name.
Once name has been introduced in the template parameter list, then any reference
to name within the body of the template automatically refers to the type of n the
corresponding template argument for each instantiation, and can be used anywhere
a type can normally be used. e.g.
template<typename T>
void func(T value)
{
const T& ref=value;
T* p=new T;
T temp(23);
}
The code generated for func<int> is then identical to:
void func(int value)
{
const int& ref=value;
int* p=new int;
int temp(23);
}
If, however, a reference was made to func<std::string>, then a compilation error
would result, as the statement
std::string temp(23); is not valid.

34

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

4.2.3. Template Non-Type Parameters


Non-Type Template Parameters are template parameters that are values rather than
types. They can be any value that is a compile-time constant 2. Their syntax is akin
to a variable declaration, e.g.
template<int i>
class A{ };
template<double* dp>
class B{
};
template<void (*func) (int)>
void c() { }
Class template A has a non-type template parameter which is an integer, class tem-
plate B has a non-type template parameter which is a pointer-to-double,
and function template c has a non-type template parameter which is a pointer to a
function returning void, with a single int parameter.
Examples of uses are:
A<3> a3;
A<sizeof(std::string)> as;
double d; // at global scope
B<&d> bpd;
B<NULL> bn;
void myfunc(int);
struct MyClass
{
static void staticFunc(int);
};
int main()
{
c<&myfunc>();
c<&MyClass::staticFunc>();
}
Within the definition of the template, the name of the non-type template parameters
refers to a constant of the appropriate type,
so given

35

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

template<int i>
void func()
{
std::cout<<i<<std::endl;
}
func<3>() will print 3, and func<999>() will print 999.
A compile-time constant is something that can be evaluated at compile-time, such
as an integer, or the address of a global variable.
There are restrictions on what can be a compile-time constant, e.g. floating point
values can not be compile-time constants.

4.2.4. Template Template Parameters


Template Template Parameters enable a template to be parameterized by the name
of another template. For example, a class which contains a couple of collections
of items, some strings, some integers, and the users of the class are to choose what
type of collection to use (vector, list, stack, etc.). The natural thought is to make the
collection type a template parameter. However, a collection of strings is a different
type from a collection of integers, so the user would have to specify both individu-
ally if template type parameters are used. To do so a Template Template Parameter
is used.
template<template<typename T> class ContainerType>
class MyClass
{
ContainerType<int> intContainer;
ContainerType<std::string> stringContainer;
// rest of class
};
ContainerType is a Template Template Parameter that refers to a template with a
single Template Type Parameter.
Hence MyClass<vector> or MyClass<list> can be said to have vectors or lists re-
spectively.
Within the template definition, the Template Template Parameters can be used just
like any other template.

36

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

4.2.5. Default Template Parameters


Just as functions can have default values for their arguments, so can templates –
and this facility works in much the same way. If a template parameter has a default
specified, then all subsequent template parameters must also have a default speci-
fied. When referencing a template, parameters with default values can be omitted;
if a template parameter is omitted, all subsequent template parameters must also be
omitted. e.g.
template< typename T1,typename T2=int,int i=23>
class MyClass
{
};
// specify all parameters
MyClass<double,std::string,46> mc1;
// omit "i"
MyClass<std::string,double> mc2;
// same as above
MyClass<std::string,double,23> mc3;
// all default
MyClass<int> mc4;
// we must specify "T2" if we wish to specify "i"
MyClass<int,int,0> mc5;
The syntax for declaring a default value for a template parameter is simple just add
”= default-value” to the parameter declaration, as shown in the example.
If a template parameter is omitted when referencing the template, then the default
value is substituted instead. If you wish to use std::vector or std::list
with aTemplate Type Parameter, then you have to take account of the additional
Allocator template parameter, even though it is very rarely specified explicitly.

4.2.6. Dependent Names


A Dependent Name is any name within a template definition that depends on one or
more of the template parameters. This includes the template parameters themselves
and other templates instantiated with template arguments that are dependent names
in the current expansion. Dependent names are important, because they are only
resolved when the template is instantiated. As a consequence of this, dependent

37

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

names that are members of types that are themselves dependent names are always
assumed to name objects or functions rather than types,unless preceded with the
typename keyword. e.g.
struct X
{
int x;
typedef double Z;
};
struct Y
{
typedef int x;
double Z;
};
template<typename T>
struct ZZ
{
T::Z z1;// 1
typename T::Z z2; // 2
void func(T& t)
{
t.x=4; // 3
}
typedef typename std::vector<T>::iterator VecIt; // 4
};
int main()
{
X x;
Y y;
ZZ<X> zzx; // 5 ZZ
<Y> zzy; // 6
zzx.func(x); // 7
zzy.func(y); // 8
}

38

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

The line marked 1 is illegal, as T::Z is assumed to refer to an object or function


rather than a type. Line 2 is the correct way of doing things.
At line 3, t.x is adependent name, but it refers to an object so this is OK. At line 4,
std::vector<T>::iterator is a dependent name that refers to a type,
so we need the typename keyword. Lines 5 and 6 instantiate the template for the
types X and Y. Line 5 is OK, because X::Z is a type,but line 6 is not,
as Y::Z is an object. Lines 7 and 8 demonstrate the opposite - X::x is OK because it
is an object, but Y::x is a type, so the instantiation of ZZ<Y>::func will fail.

4.3. Using Templates


Class templates and function templates can be used anywhere normal classes and
functions can be, as well as as Template Template Parameters (2.1.3) to other tem-
plates. However, the compiler needs to know what to use for the template parame-
ters. For class templates, the template name must be followed by a template argu-
ment list, specifying the parameters. This is a comma-separated list of expressions
between angle brackets (<>). For Template Type Parameters, the corresponding ex-
pression must name a type, for Template Non-Type Parameters, the expression must
evaluate to a compile-time constant of the appropriate type, and for Template Tem-
plate Parameters, the expression must name a template with the correct signature.
e.g.:
template<typename T,unsigned i>
struct FixedArray
{
T data[i];
};
FixedArray<int,3> a; // array of 3 integers
FixedArray<int,1+6/3> b; // array of 3 integers
template<template<typename T,typename Allocator> class Container>
struct ContainerPair
{
Container<int,std::allocator<int> > intContainer;
Container<std::string,std::allocator<std::string> > stringContainer;
};
ContainerPair<std::deque> deqCont; // two std::deques

39

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

ContainerPair<std::vector> vecCont; // two std::vectors


The second example demonstrates two things. Firstly, the template signature of the
Template Template Parameter must exactly match the signature of the
template passed as the argument, and standard containers have two template param-
eters. Secondly, if the last argument of a template parameter list is
a template reference, as for Container<int,std::allocator<int> >, then the two clos-
ing angle brackets (>) must be separated by a space, to avoid being
interpreted as the shift right operator (>>). For function templates, there are two
options for specifying the template parameters. Firstly, the function name
can be followed by a template argument list as for class templates, e.g.:
template<typename T>
void func()
{
}
int main()
{
func<int>();
func<double>();
}
The second alternative is for function template where one or more of the template
parameters are used in the function parameter list. In this case, it is possible
to omit those template parameters from the template argument list, as if they had a
default value specified (2.2). e.g.:
7
template<typename T>
void func(T value)
{}
template<typename T,typename U>
T func2(U value)
{
return T(value);
}
int main()
{

40

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

// T=int
func(3);
// T=double
func(3.5);
// T=int, U=double
func2<int>(3.5);
// T=std::vector<std::string>, U=int
func2<std::vector<std::string> >(5);
// specify both T and U
// T=std::vector<std::string>, U=int
func2<std::vector<std::string>,int>(5.7);
}
This Template Argument Deduction can be used to make life easier for the user of
a function template, the same way that function overloading makes life
easier for the user of a normal function - the correct function instantiation is auto-
matically called based on the function arguments provided.
In some circumstances, Template Argument Deduction will fail, because there is an
inconsistency caused during deduction - if two parameters are declared
to be the same type, and different types are passed, then the compiler cannot deduce
which to use. This often occurs with std::max: int i=std::max(3,4.5);
The compiler cannot deduce whether to instantiate std::max<int>(int,int) or std::max<double>(double,do
so it generates an error. The solution is to
provide an explicit template argument list, or cast one of the arguments so it is the
same type as the other.
int i=std::max(static_cast<double>(3),4.5);
// T=double int j=std::max<int>(3,4.5);
// T=int
Note also that the return type is not considered when deducing the template argu-
ments in this way. The Standard C++ Library contains a large number
of templates, which is partly what makes it so powerful - the Standard Library code
can be successfully used with classes that didn’t exist when the
Standard was written.

41

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

4.4. Template Requirements and Concepts


Templates implicitly impose requirements on their parameters, particularly Tem-
plate Type Parameters and Template Template Parameters . These requirements
generally take the form of operations that must work on objects of the appropriate
type, or class members that must exist and refer to objects or types or functions
(with the implicit extra requirement that the type referred to is a class). A Con-
cept is a set of requirements that describe a useful feature of a type. For example,
the C++ Standard Library makes reference to things being Assignable or Copy-
Constructible; these are Concepts that make the following requirements: Given a
type T, that type is Copy-Constructible if the expression T a(b); is defined, where
b is an expression of type T, and the resultant object a has a value equivalent to the
value of the expression b. That type is Assignable if the expression
a=b;is defined, where a and b are expressions of type T, and the value of the object
referred to by the expression a is equivalent to the value of the object referred
to by the expression b after the assignment.
All built-in types are both Copy-Constructible and Assignable. For classes, these
requirements translate into requirements on member functions:

• A class T is Copy-Constructible if it has a constructor which can be called


with one argument of type constreference- to-T. This may be a constructor
with one argument, or it may be a constructor with more than one argument,
with default values provided for the remainingarguments. The object thus
constructed should have a value equivalent to that of the argument

• A class T is Assignable if it defines a copy-assignment operator (operator=())


which has an argument of type T, or const-reference-to-T. The object to which
the member function belongs should have a value equivalent to that of the
argument after the completion of such a member function.

• As a consequence, the std::auto ptr template does not fulfil these require-
ments, as it exhibits transferof- ownership semantics on copy-construction
and assignment, and consequently the copy-constructor and copyassignment
arguments are of type reference-to-T rather than const-reference-to-T. It is
possible to write Concept-checkers, templates which verify that a given type
does indeed fulfil all the syntactic requirements of a particular Concept, even

42

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

if the current template doesn’t require all of them in its current implemen-
tation. This also makes tracking down errors easier - the compilation error
generated by a failure in such a Concept-Checker is more obviously a failure
of the parameter type to fulfil the concept requirements than a failure else-
where in the template definition. It is possible that a class template may sup-
port different operations, depending on which of several concepts a parameter
type fulfils the requirements for. This is made possible by a feature of C++
class templates - member functions of class templates are only instantiated
if they are referenced. This means that a class template can have a member
function which only compiles if the template parameters fulfil a particular
concept, but the program will compile even if they don’t fulfil the concept,
provided that the function is not referenced for that set of parameters. e.g.:
4If a class does not define any copy-constructors (constructors which can be
called with a single argument of type reference-to-T or const-reference-to-
T), then the compiler will generate one automatically. 5If a class does not
define any copy-assignment operators which can be called with a single argu-
ment of type T, reference-to-T or const-reference-to-T, then the compiler will
generate one automatically.

template<typename T>
class MyClass
{
public:
T* makeCopy(T* p)
{
return p>
clone();
}
};
MyClass<int> mci;
double d;
MyClass<double> mcd;
double* pd=mcd.makeCopy(&d);
mci is fine; as no reference is made to the makeCopy member, it doesn’t matter that
int isn’t a class. However, the reference to mcd.makeCopy causes an error,

43

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

as you cannot call member functions on a double.

4.4.1. Template Specialization and Overloading


Template Specialization allows you to decide that for a specific set of template pa-
rameters, the code instantiated for a template should be different to the general case.
Say, for example, you wish to use a template with a new class as a Template Type
Parameter (2.1.1), and though it has the same semantic behaviour as the classes the
template was designed for, the syntax is different, so the original template won’t
compile with the new class as a parameter. The solution to this problem is special-
ization. Consider the following template function definition:
template<typename T>
void func(T value)
{
value.add(3);
}
This function assumes that the type substituted for the Template Type Parameter T
is a class with a member function add that takes a single parameter of a type
that can be constructed from an int. Thus the following classes would be OK:
class T1
{
public:
void add(int i,double d=0.0);
};
class T2
{
public:
std::string add(double d);
};
However, the class T3 below is not OK, because Add is has a capital A.
class T3
{
public:
void Add(int i);
};

44

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

This means that we cannot use our original function template func for T3.

4.4.2. Explicit Specialization


What we can do, however, is Explicitly Specialize the template for T3:
template<>
void func<T3>(T3 value)
{
value.Add(3);
}
There are two distinctive things about this declaration. The first is the empty tem-
plate parameter list after the template keyword, and the second is the presence
of the template argument list after the name of the function. This tells the compiler
that (a) a template is being specialized, and (b) what set of template
parameters apply for this specialization. Then, whenever the compiler needs to
instantiate the template with this set of template parameters, it uses
the specialization instead of the general template. Explicit Specialization applies
both to class templates and function templates. Here is an example for a
class template, in which the constructor for the general template accepts its param-
eter by value, but the constructor for the std::string instantiation accepts
its parameter by const-reference, for efficiency:
template<typename T>
class X
{
X(T x);
};
template<> class X<std::string>
{
X(const std::string& s);
};
Explicit Specialization can be used with recursive class templates to perform compile-
time computations. e.g.:
template<unsigned i>
struct Fibonacci
{

45

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

static const unsigned result=Fibonacci<i1>::


result+Fibonacci<i2>:: result;
};
template<> struct Fibonacci<0>
{
11 static const unsigned result=1;
};
template<> struct Fibonacci<1>
{
static const unsigned result=1;
};
int main()
{
std::cout<<Fibonacci<5>::result<<std::endl;
}
The class template Fibonacci<i> defines a constant result to be the i-th number in
the Fibonacci Sequence (1,1,2,3,5,8,13,. . . ) where every element is the sum of
the two previous ones. This can be seen in the definition of the general template
- the value of result is set to the sum of the results of the previous two elements.
However, by itself, this is not enough, as each of those is the sum of the previous
two, and so on. We solve this by introducing the two explicit specializations for
Fibonacci<0> and Fibonacci<1>, to define the first two elements in the series. This
way the expansion of the template for any value of i will eventually terminate, so
the sample main function will output 8. In addition to Explicit Specialization, there
is Partial Specialization for class templates, and Function Template Overloading for
function templates.

4.4.3. Partial Specialization


Partial Specialization allows you to specialize a class template for a subset of the
possible template parameters, where the definition of the template should be the
same for the whole subset, but different to the general case. e.g.:
template<typename T,typename U>
struct SameType
{

46

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

static const bool result=false;


};
template<typename T>
struct SameType<T,T>
{
static const bool result=true;
};
int main()
{
std::cout<<"Is int the same type as double?"
<<(SameType<int,double>::result?"Yes":"No")<<std::endl;
std::cout<<"Is std::string the same type as std::string?"
<<(SameType<std::string,std::string>::result?"Yes":"No")<<std::endl;
}
The partial specialization of the class template SameType looks a bit like a normal
template definition (the Template Parameter List is not empty),
and a bit like an explicit specialization (there is a Template Argument List after
the template name). The compiler knows it is a partial specialization, because both
these things are present. The partial specialization applies to all instantiations of
the class template where the full template argument list supplied for the general
definition can be written down in the form for the partial specialization. In this
example, the partial template specialization applies if both types are the same, so if
the types are the same, the value of result is true, whereas if they are different, the
general definition applies, and the value of result is false. Therefore the example
main function will output: Is int the same type as double?No Is std::string the same
type as std::string?Yes Partial Specialization can be used for very fine control over
what template definition is used. For example, it is possible to specialize on the
const-ness of a template type parameter, or for template type parameters which are
templates:
template<typename T>
struct IsConst
{
static const bool result=false;
};

47

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

template<typename T> struct IsConst<const T>


{
static const bool result=true;
};
template<typename T> struct IsVector
{
static const bool result=false;
};
template<typename T> struct IsVector<std::vector<T> >
{
static const bool result=true;
};
Thus the result member of IsConst is only true if the template parameter is a const
type, and the result member of IsVector is only true if the template parameter
is an instantiation of the std::vector template.

4.4.4. Function Template Overloading


You cannot partially specialize a function template, but function templates can be
overloaded, much the same as functions can be overloaded. This means you can
define multiple function templates with the same name, but different template pa-
rameters, or a different function signature. You can use this to much the same effect
as you can use partial specialization of class templates. Consider the function tem-
plate swap:
template<typename T>
void swap(T& lhs,T& rhs)
{
13 T temp(lhs);
lhs=rhs; rhs=temp;
}
This is generally sufficient to swap two values of any type that is copy-constructible,
and assignable. However, it creates a new object (temp), and copies
data three times. If this template is instantiated for a class that is expensive to copy,
then it could be very inefficient. To ease this, we add a member function

48

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

swap to our class which swaps the value with that of another object as efficiently as
possible
class ExpensiveToCopy
{
public:
void swap(ExpensiveToCopy& other);
};
To call this, we now say a.swap(b) rather than swap(a,b), which is inconsistent. We
can solve this by specializing the function template swap
for ExpensiveToCopy:
template<>
void swap<ExpensiveToCopy>(ExpensiveToCopy& lhs,ExpensiveToCopy& rhs)
{
lhs.swap(rhs);
}
All is well and good, but what if ExpensiveToCopy was a class template, such as
std::vector; we don’t want to have to specialize swap for every
possible instantiation of the template. The solution to this is Function Template
Overloading - we just write a new template function which overloads the
first, e.g.:
template<typename T>
void swap(std::vector<T>& lhs,std::vector<T>& rhs)
{
lhs.swap(rhs);
}
The compiler chooses which overloaded template to instantiate for each call using
a mechanism called Partial Ordering in addition to the normal
overload resolution. This is quite complicated, but essentially results in more spe-
cific overloads, like that of swap for std::vector being preferred to the
more general equivalent, if the actual parameters are compatible with the more
specific one. If Function Template Overloading does not suit your needs, and
you really do need Partial Specialization (4.2), the only option is to write a helper
class template, with a single static member function that does all the work,

49

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

and have your function template forward to this function. You can then partially
specialize the helper class template to change the body of the static member. e.g.:
template<typename T>
class MyClass
{
public:
void write(std::ostream& os) const;
};
14 template<typename T>
struct PrintDataHelper
{
static void doPrint(T value)
{
std::cout<<"The data is "<<value<<std::endl;
}
};
template<typename T> struct PrintDataHelper<MyClass<T> >
{
static void doPrint(const MyClass<T>& value)
{
std::cout<<"The data is "; value.write(std::cout);
std::cout<<std::endl;
}
};
template<typename T> void printData(T value)
{
PrintDataHelper<T>::doPrint(value);
}

4.5. Summary.
This module provides an insight into how they work and how they can be utilised
to make the task of writing and maintaining software easier. They provide immense
scope for writing generic and customizable classes and functions, and form an es-

50

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

sential C++ language feature, without which much of the Standard C++ Library
couldn’t exist, or would be greatly restricted.
C++ templates are a powerful mechanism for code reuse, as they enable the pro-
grammer to write code that behaves the same for data of any type.
Partial Specialization allows you to specialize a class template for a subset of the
possible template parameters, where the definition of the template should be the
same for the whole subset, but different to the general case.

51

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

Revision Questions

Example . Explain how to define templates in C++


Solution: A Template Definition starts with the keyword template, followed by
a list of Template Parameters What follows is then either a class definition, or a
function definition, defining a class template or a function template respectively.
The template parameters introduce names into the scope of the definition, which
can be types, values or templates. 

E XERCISE 13.  Diiferentiate between template specialization and overloading.


E XERCISE 14.  Using an example of code explain class template.
E XERCISE 15.  Discuss function template overloading.
E XERCISE 16.  Using a program explain Template Template Parameters in C++.

52

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

LESSON 5
Introduction notes on files programming

Learning outcomes
Upon completing this topic, you should be able to:

• Understand Files

• Understand Input and Output files

• Write a program that can write and read a text from a file.

• Understand the importance of file programming.

5.1. Basics in file programming


Remember all a long we have been dealing with input and output streams this whole
time which are cin and cout respectively. The input/output stream is used with
the <iostream>library. In C++, as well as any programming language, you can
read and write to a text file (.txt extension). This is done in a similar way to the
input/outputstream intermsof the library to include with the program.
C++ provides 3 of them:

• #include <ifstream>:Library to specifically deal with input of text files. Does


not deal with output.

• #include <ofstream>:Library to specifically deal with output of text files.


Does not deal with input.

• #include <fstream>:Library to deal with BOTH input and output.

One important thing to note is that the input is treated the same as cin while the
output is treated the same as cout.

53

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

5.1.1. Output
In order to do both input or output, you must open a file before anything else occurs.
The same as a variable, the stream you are using is a type. So here is a short program
that shows some simple output to a text file.
Example 1:
Simple output
#include <iostream>
#include <fstream>
using namespace std;
int main ()
{
//declare the variable of type ofstream
//since you are dealing with output:
ofstream myfile;
//function to open the file which includes
//the file name:
myfile.open ("example.txt");
//check if the file is open with the is_open()
//function: if(myfile.is_open())
{
//preform the operation(s):
myfile << "Hello world! This is output!" << endl;
//function to close the file: myfile.close();
}
else{
//is_open() returned false and there is a problem: cout << "Can’t open the file!" <<
endl;
}
return 0;
}
The above program will simply open a text file for output (ofstream), check to see
if the file is correctly opened, write a line to the file and close the stream.
Here is a bit more detail about the above programs functions.

54

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

• open()

The open() function will simply open a file for either input or output. The above
program did it for output. The parameter of the function will be the file name.
If the file does not exist in the directory, C++ will create it for you.

• close()

A simple function designed to close the file and it’s stream. It will require no
parameters.

• is_open()

The is_open() function is a boolean function that will check whether or not a file is
open. If the function returns true, the file is open without any problems. If it returns
false, the file is not good and therefore cannot be used.

5.1.2. Input
Recalling from the previous tutorial about the getline() function, input from text
filesare used in that fashion. Input of files also require the <string>library for the
getline() function. Here is an example of file input. The file must be created first in
order for this to work.
Example 2:
Simple input
// reading a text file
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main ()

55

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

{
string line;
//the variable of type ifstream: ifstream myfile ("example.txt");
//check to see if the file is opened:
if (myfile.is_open())
{
//while there are still lines in the //file, keep reading:
while (! myfile.eof() )
{
//place the line from myfile into the //line variable: getline (myfile,line);
//display the line we gathered: cout << line << endl;
}
//close the stream: myfile.close();
}
else cout << "Unable to open file";
return 0;
}
This program will attempt to read a file for input, display the line you read and then
close the file. Here is some information about the new function eof()
which stands for "end of file".
eof()
The eof() function is a boolean function that will check whether or not the file has
reached the end. It returns true when the file is at the end and false otherwise.
5.2. Writing data to file
The commands for writing data to a file are (for the most part) very similar to those
used to write data to the screen.. In order for your program to write to a
file, you must:

1. Include the fstream header file and using std::ostream;

2. declare a variable of type ofstream

3. open the file

56

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

4. check for an open file error

5. use the file

6. close the file when access is no longer needed (optional, but a good practice)

Example. How write data into a file.


#include <iostream>

using std::cerr;
using std::endl;
#include <fstream>
using std::ofstream;
#include <cstdlib>
// for exit function
// This program output values from an array to a file named example2.
dat int main()
{
ofstream outdata;
// outdata is like cin int i;
// loop index int num[5] = {4, 3, 6, 7, 12};
// list of output values outdata.open("example2.dat");
// opens the file if( !outdata )
{
// file couldn’t be opened cerr << "Error: file could not be opened" << endl;
exit(1);
}
for (i=0; i<5; ++i)
outdata << num[i] << endl;
outdata.close();
return 0;
}
In this example, the variable outdata is declared as type ofstream. It is used in the
same way that cout is used for doing output to the screen. Several values may be
written to the same output record as follows:

57

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

outdata << num1 << " " << num2 << " " << num3 << endl;
Spaces are inserted in this statement to separate the output values. When opening
a file, you should always check for success before continuing. The ! operator for
the filename returns true if the file can’t be opened. You might want to use the
following stream manipulators: hex, dec, setw, setfill.
You might also be using the following arguments to setf, unsetf, setiosflags and
resetiosflags: ios::uppercase, ios::left, ios::right. Use of stream manipulators re-
quires the iomanip header file and appropriate using declarations.

5.3. Reading data from a file


Data is stored in files so that it may be retrieved for processing when needed. The
commands for reading data from a file are (for the most part) very similar to those
used to read data from the keyboard. In order for your program to read from the
file, you must:

1. include the fstream header file with using std::ifstream;

2. declare a variable of type ifstream

3. open the file

4. check for an open file error

5. read from the file

6. after each read, check for end-of-file using the eof() member function

7. close the file when access is no longer needed (optional, but a good practice)

Example. #include <iostream>

using std::cerr;
using std::cout;
using std::endl;
#include <fstream>
using std::ifstream;
#include <cstdlib> // for exit function

58

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

// This program reads values from the file ’example.dat’


// and echoes them to the display until a negative value
// is read. int main()
{
ifstream indata;
// indata is like cin int num;
// variable for input value indata.open("example.dat");
// opens the file if(!indata)
{
// file couldn’t be opened cerr << "Error: file could not be opened" << endl;
exit(1);
}
indata >> num;
while ( !indata.eof() )
{
// keep reading until end-of-file cout << "The next number is " << num << endl;
indata >> num;
// sets EOF flag if no value found
}
indata.close();
cout << "End-of-file reached.." << endl;
return 0;
}
In this example, the variable indata is declared as type ifstream. It is used in the
same way that cin is used for doing input from the keyboard. The statement indata
>> num; reads characters from the file and converts them to a data value of the
appropriate type-in this case integer. In doing so, whitespace characters are skipped
over; the same action takes place in the case of reading into a variable of type char,
float or double.
(Whitespace characters include space,tab, newline).
Several values my be read using the same input statement. For example: indata
>> num1 >> num2 >> num3; When opening a file, you should always check for
success before continuing. The ! operator for the filename returns true if the file

59

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

can’t be opened. The value of indata.eof() is true if the most recent attempt to read
a value was unsuccessful (i.e. no more data).
The following example shows how to read one character at a time.
char letter;
// variable for input value
indata >> letter;
while ( letter != ’Q’ )
{
cout << letter;
indata >> letter;
}
cout << endl;
INPUT: ab 12 3Q
OUTPUT: ab123
The above example reads and echoes characters from the file until the letter Q is
encountered, at which point the program stops.
Note that the spaces (whitespace) are skipped over and do not appear in the output-
only 6 characters are actually read.
The next example shows how to read an entire string using the >> operator.
char word[10]; // variable for input value
indata >> word;
cout << word << endl;
INPUT1: ab123 5670 sdQzx | INPUT2: abcdefghijklmnop qrstuvwxyz
OUTPUT1: ab123 | OUTPUT2: ?????????????
When reading character values into a string variable using >> , characters are read
until whitespace is encountered. It is the programmer’s responsibility to make sure
that the string variable is large enough to store all the characters that are read.
Thus, for INPUT1, the characters ’ab123’ are read and stored in the variable word.
The space between the ’3’ and the ’5’ terminates the read operation.
In the second example, the programmer made a mistake since the string has only
space for 10 characters, but the computer would continue reading up to the letter
’p’. The actual output in this situation would depend on the computer used. In some
situations, it is desirable to read an entire line of input, including the whitespace.

60

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

For example: to read a name such as ’ JKUAT community’ into a single string
variable. This can be done using the getline member function.
char word[10]; // variable for input value
indata.getline(word, 10, ’\n’);
cout << word << end;
INPUT1: abcdefg // entire line is read into word
OUTPUT1: abcdefg INPUT2: abcdefghiABCDEFGHIJ // first 9 chars are read in
OUTPUT2: adcdefghi
In this example, the getline function will read characters from the file, placing them
in the array word, until 9 characters have been read (leaving one space for the NULL
character) or until the delimiter ’\n’ is read. If there are more than 9 characters on
the line, then those ’extra’ characters remain in the input buffer.
If there are 8 or fewer characters, the whole line is read in and the delimiter is re-
moved from the buffer. Note that if there are exactly 9 characters, then the delimiter
is not removed from the buffer. The peek() function is used to read one character
from the input stream while leaving the character in the buffer.
The character will be read with the next input statement. The putback() function is
used to return the character most recently read to the input stream.

5.4. Reading Text Files(revisited)


Reading a text file is very easy using an ifstream (input file stream).

1. Include the necessary headers.

2. #include <fstream> using namespace std;

3. Declare an input file stream (ifstream) variable. For example, ifstream inFile;

4. Open the file stream. -Path names in MS Windows use backslashes (\). Be-
cause the backslash is also the string escape character, it must be doubled. If
the full path is not given, most systems will look in the directory that contains
the object program. For example, inFile.open("C:\\temp\\datafile.txt");

5. Check that the file was opened. For example, the open fails if the file doesn’t
exist, or if it can’t be read because another program is writing it.

61

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

A failure can be detected with code like that below using the ! (logical not)
operator:
if (!inFile)
{ cerr << "Unable to open file datafile.txt";
exit(1); // call system to stop
}

6. Read from the stream in the same way as cin.


For example, while (inFile >> x)
{
sum = sum + x;
}

7. Close the input stream.

Closing is essential for output streams to be sure all information has been written to
the disk, but is also good practice for input streams to release system resources and
make the file available for other programs that might need to write it.
inFile.close();

Example
The following program reads integers from a file and prints their sum.
// io/read-file-sum.cpp - Read integers from file and print sum.
// The author of the module.E.O.O
#include <iostream>
#include <iomanip>
#include <fstream>
using namespace std;
int main()

62

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

{
int sum = 0;
int x;
ifstream inFile;
inFile.open("test.txt");
if (!inFile)
{
cout << "Unable to open file";
exit(1);
// terminate with error
}
while (inFile >> x)
{
sum = sum + x;
}
inFile.close();
cout << "Sum = " << sum << endl;
return 0;
}
5.4.1. Reading numbers
Read from in a while loop
The standard C/C++ style for reading is to put the read operation in a while loop
condition. If the read proceeds correctly, then the value is true. If there is an end-
of-file (EOF) meaning that the end of the data has been reached, or if there is an
error in reading, then the value returned is false and execution continues at the end
of the loop.
Example :Adding numbers in the input
int sum = 0;
int x;
while (cin >> x)
{
sum += x;
}
cout << sum;

63

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

The following code does almost the same thing as the code above, but it has disad-
vantages.
int sum = 0;
int x;
cin >> x;
// BAD idiom for input.
while (cin)
{
// Required by inadequate Pascal I/O.
sum += x;
// Should not be used in C++.
cin >> x;
}
cout << sum;
5.4.2. Reading Lines
These notes are written using cin as an example, but they apply to all input streams.
Strings (sequences of characters) are stored two different ways in C++. C-strings
are arrays of characters with a terminating zero value at the end.
There is also a string class in the C++ standared library. In general, it’s better to use
the string class, but many times that C-strings must be used.
Reading a line into a string
string s;
...
while (getline(cin, s))
{
// s contains the input line, without final newline char
....
}
Reading a line into a C-string
char ca[100];
...
while (cin.get(ca, 99))
{
// ca has one input line without crlf and with terminating 0

64

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

...
}
5.4.3. Reading Characters
These notes are written using cin as an example, but they apply to all input streams.
How to work with whitespace
The standard input stream (cin) does just what you want when reading integers,
floating point etc. It ignores all whitespace (blanks, tabs, etc) that appears in front
of a number. But when you’re reading characters, you will often want to read
whitespace too. For example, here’s a little loop to count the number of characters
in the input stream.
char c;
int count = 0;
while (cin >> c)
{
// DOESN’T READ WHITESPACE!!!!!
count++;
}
This fails to give an accurate count of characters because it ignores all the whites-
pace characters. There are two solutions.
• Use the noskipws I/O manipulator to cause a further cin reads to not ignore whites-
pace (or until the skipws manipulator is used).
Here’s that same loop rewritten.
• char c;
• cin >> noskipws;
// Stops all further whitespace skipping
• while (cin >> c)
{
// Reads whitespace chars now.
• count++;
}
This isn’t a bad solution, but if you need to switch back and forth between skipping
whitespace and not, the best approach is the next alternative.
• Use the cin.get() function.
• char c;

65

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

• while (cin.get(c))
{
// Always reads whitespace chars.
• count++;
}
Read one line with cin.get(...) or cin.getline(...)
char ca[100];
...
while (cin.get(ca))
{
// ca has one input line without crlf and with terminating 0
...
}
Ignoring input
When an error is encountered, it is often useful to skip all remaining characters on
the line. You can do that with:
cin.ignore(n, c); where n is the number of characters to skip, and c is the character
to skip up to, whichever comes first.
For example, to skip to the end of the line, cin.ignore(1000, ’\n’);
5.5. Summary on I/O streams
File handling is an important part of all programs. Most of the applications will
have their own features to save some data to the local disk and read data from the
disk again. C++ File I/O classes simplify such file read/write operations for the
programmer by providing easier to use classes.
C++ File I/O Classes and Functions:
There are 3 File I/O classes in C++ which are used for File Read/Write operations.
They are

• ifstream - Can be used for File read/input operations

• ofstream - Can be used for File write/output operations

• fstream - Can be used for both read/write c++ file I/O operations

66

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

The most important methods which will be used for any file operations are:

1. 1. fstream::open method - to open the file

2. 2. fstream::Operator >> and fstream::Operator << - For reading from or writ-


ing to the file.

3. 3. fstream::close - Flushes all buffer and close the file

Reading a text file using fstream class:


There are several ways of reading the text from a file. But all of them have a
common approach as follows.

1. Open the file

2. Read the data

3. Close the file This sample code snippet explains how to use the c++ file i/o
stream operators to read data from a file.

In all cases the header file fstream.h must be included.


#include<fstream.h>
int main()
{
char str[2000];
fstream file_op("c:\\test_file.txt",ios::in);
while(file_op >> str)
cout << str ;
file_op.close();
return 0;
}
The class fstream, which is used above is the one which is commonly used for c++
file i/o manipulations. The constructor of fstream takes 2 parameters.

67

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

One is the file path and the second is the File Open mode. There are several open
modes, each of them with a different purpose. Some of them are ios::
in for reading, ios::out for writing, ios::app for appending to the end of file, ios::binary
for opening in binary mode etc.,
Now for the purpose of this article, as the data is read from the file, the flag ios::in
is used. After this, the read operation is continued till the end of the file.
The while loop ensures a continuous read till the end of the file or it encounters any
abnormal break. If the program is built and run , it displays all the data
read from the file. The C++ File I/O read job is done.
But if we look at the output closely, there is a draw back in using this stream oper-
ator read.
The output misses the white spaces and the end of line characters. In order not to
miss these characters we can either use fstream::get() or fstream::getline
() methods.
Here is the example for using fstream getline method.
#include <fstream.h>
int main()
{ char str[2000];
fstream file_op("c:\\test_file.txt",ios::in);
while(!file_op.eof())
{ file_op.getline(str,2000);
cout <<str;
}
file_op.close();
cout <<endl;
return 0;
}

Writing to a text file using fstream class:


Writing to a text file can also be achieved with the stream operators. This also
follows the same order of operations, though with a slight difference.

1. open a file - in write mode

68

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

2. Write to a file

3. close the file

Look at the following sample code to see the difference.


#include <fstream.h>
int main()
{
fstream file_op("c:\\CoderSource_file.txt",ios::out);
file_op<<"Test Write to file"; file_op.close();
return 0;
}
To modify the data or to seek to a different position inside the file, the c++ file i/o
class fstream provides member functions like seekg() etc., These functions
can be used to relocate the record insert position to the desired locations. After all
the C++ File I/O operations we do a fstream::close(), to close the file
pointer. This is not mandatory. Even if this function is not called by the application,
the destructor of the fstream class will close the file when the object goes
out of scope.

Stream Manipulators (defined in <iomanip>)


Dec →Sets base 10 integers.
Endl -Sends a new line character.
Ends- Sends a null (end of string) character.
Flush -Flushes an output stream.
Fixed -Sets fixed real number notation.
Hex- Sets base 16 integers.
oct- Sets base 8 integers. ws Discard white space on input. setbase(int) Sets integer
conversion base (0, 8, 10 or 16 where 0 sets base 10).
setfill(int) -Sets fill character.
setprecision(int)- Sets precision.
setw(int)- Sets field width.
resetiosflags(long)- Clears format state as specified by argument.

69

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

setiosflags(long) -Sets format state as specified by argument.


Stream Member Functions
void .close() -Closes the I/O object.
int .eof() -Returns a nonzero value (true) if the end of the stream has been reached.
Use after fail() returns true.
char .fill(char fill_ch | void) -Sets or returns the fill character.
int .fail() -Returns a nonzero value (true) if the last I/O operation on the stream
failed.
istream& .get(int ch) Gets a character as an int so EOF (-1) is a possible value.
istream& .getline(char* ch_string, int maxsize, char delimit) -Get a line into the
ch_string buffer with maximum length of maxsize and ending with
delimiter delimit.
istream& .ignore(int length[, int delimit]) -Reads and discards the number of char-
acters specified by length from the stream or until the character specified
by delimit (default EOF) is found.
iostream& .open(char* filename, int mode) -Opens the filename file in the specified
mode.
int .peek();- Returns the next character in the stream without removing it from the
stream.
int .precision(int prec | void) -Sets or returns the floating point precision.
ostream& .put(char ch) -Puts the specified character into the stream.
istream& .putback(char ch)- Puts the specified character back into the stream.
istream& .read(char* buf, int size) -Sends size raw bytes from the buf buffer to the
stream.
long .setf(long flags [, long mask]) -Sets (and returns) the specified ios flag(s).
long .unsetf(long flags)- Clears the specified ios flag(s).
int .width(int width | void)- Sets or returns the current output field width.
ostream& .write(const char* buf, int size) -Sends size raw bytes from buf to the
stream.
IOS Format Flags (ios::x)
dec -Use base 10.
fixed Output float values in fixed point format (use the resetiosflags(ios::floatfield)
manipulator or the unsetf(ios::floatfield)- function to reset to default format). hex
-Use base 16.

70

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

internal Distribute fill character between sign and value. left Align left.
oct -Use base 8.
right -Align right.
scientific Outputs float values in scientific format (use the resetiosflags(ios::floatfield)
manipulator or the unsetf(ios::floatfield) function to reset to
default format).
showbase -Encodes base on integer output.
showpoint -Include decimal point in output.
showpos-Include positive (+) sign in output.
skipws -Skip white space (spaces and tabs).
uppercase- Forces upper case output.
IOS File Access Flags (ios::x)
app- Open in append mode.
ate -Open and seek to end of file.
in- Open in input mode.
nocreate -Fail if file doesn’t already exist.
noreplace -Fail if file already exists.
out -Open in output mode.
trunc -Open and truncate to zero length.
binary- Open as a binary stream.
Example 1
#include<iostream.h>
#include<fstream.h>
#include<stdlib.h>
int main()
{
fstream optfil;
optfil.open("text.txt",ios::out);
char name[10];
if(optfil.fail())
{
cerr<<"The file not opened";
exit(1);
}

71

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

cout<<"enter your name";


cin>>name; optfil<<name;
cout<<"Enter you age";
int age;
cin>>age;
optfil<<age;
optfil.close();
fstream inpfil;
inpfil.open("clas.cpp",ios::out);
if(inpfil.fail())
{
cerr<<"file cannot be opened";
exit(1);
}
inpfil>>name;
inpfil>>age;
optfil<<"your name is" <<name<<"and age is"<<age;
inpfil.close();
return 0;
}
Example 2
#include <iostream.h>
//using std::cerr;
//using std::endl;
//using namespace std::out;
#include <fstream.h>
//using std::ofstream;
#include <stdlib.h>
// for exit function
// This program output values from an array to a file named example2.dat
int main()
{
ofstream outdata;
// outdata is like cin int i;

72

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

// loop index int num[5] = {4, 3, 6, 7, 12};


// list of output values outdata.open("textloop.txt",ios::out);
// opens the file if( !outdata )
{
// file couldn’t be opened cerr << "Error: file could not be opened" << endl;
exit(1);
}
for (i=0; i<5; ++i)
outdata<< num[i] << endl;
outdata.close();
return 0;
}

73

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

Revision Questions

Example . Name main three libraries that are used in C++ for file programming
Solution: #include <ifstream>:Library to specifically deal with input of text files.
Does not deal with output.
#include <ofstream>:Library to specifically deal with output of text files. Does not
deal with input.
#include <fstream>:Library to deal with BOTH input and output. 

E XERCISE 17.  Differentiate between writing and reading to a file

E XERCISE 18.  Name three main issues to consider before perforing a write
operation on a file

E XERCISE 19.  Differentiate between peek() and seekg() function in file pro-
gramming.

E XERCISE 20.  Explain the following file mode parameters.


Ios::ate
Ios::noplace
Ios::at
Ios::nocreate.

Problem. Write a program code that be used open a file “son.doc” using a construc-
tor function,and use a member function open of the class.You should also write the
word “sons of the people” on to the file.

74

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

LESSON 6
Early binding and late binding

Learning outcomes
Upon completing this topic, you should be able to:

• Understand the binding.

• Differentiate Static and Dynamic binding.

• Discuss the importance static and dynamic binding.

• Write a program code that explains the static and dynamic binding.

6.1. Introduction to Binding


When a C++ program is executed, it executes sequentially, beginning at the top of
main(). When a function call is encountered, the point of execution jumps to the
beginning of the function being called. How does the CPU know to do this?
When a program is compiled, the compiler converts each statement in your C++
program into one or more lines of machine language. Each line of machine lan-
guage is given it’s own unique sequential address. This is no different for functions
— when a function is encountered, it is converted into machine language and given
the next available address. Thus, each function ends up with a unique machine
language address.
Binding refers to the process that is used to convert identifiers (such as variable
and function names) into machine language addresses. Although binding is used
for both variables and functions, in this lesson we’re going to focus on function
binding.

6.2. Early binding


Most of the function calls the compiler encounters will be direct function calls. A
direct function call is a statement that directly calls a function. For example:
#include <iostream>
void displayVal(int Val)

75

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

{
std::cout << Val;
}
int main()
{
displayVal(7);
// This is a direct function call
return 0;
}
Direct function calls can be resolved using a process known as early binding. Early
binding (also called static binding) means the compiler is able to directly associate
the identifier name (such as a function or variable name) with a machine address.
Remember that all functions have a unique machine address. So when the compiler
encounters a function call, it replaces the function call with a machine language
instruction that tells the CPU to jump to the address of the function.
This is a simple calculator program that uses early binding:
#include <iostream>
using namespace std;
int Add(int i, int j)
{
return i + j;
}
int Subtract(int i, int j)
{
return i- j;
}
int Multiply(int i, int j)
{
return i * j;
}
int main()
{
int i;
cout << "Enter a number: ";

76

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

cin >> i;
int j;
cout << "Enter another number: ";
cin >> j;
int op;
do
{
cout << "Enter an operation (0=add, 1=subtract, 2=multiply): ";
cin >> op;
}
while (op< 0 || op > 2);
int Results = 0;
switch (op)
{
case 0: Results = Add(i,j);
break;
case 1: Results = Subtract(i,j);
break;
case 2: Results = Multiply(i,j);
break;
}
cout << "The answer is: " << Results << endl;
return 0;
}
Because Add(), Subtract(), and Multiply() are all direct function calls, the compiler
will use early binding to resolve the Add(), Subtract(), and Multiply() function
calls. The compiler will replace the Add() function call with an instruction that
tells the CPU to jump to the address of the Add() function. The same holds true for
Subtract() and Multiply().

6.3. Late Binding


In some programs, it is not possible to know which function will be called until
runtime (when the program is run). This is known as late binding (or dynamic

77

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

binding). In C++, one way to get late binding is to use function pointers. To review
function pointers briefly, a function pointer is a type of pointer that points to a
function instead of a variable. The function that a function pointer points to can
be called by using the function call operator (()) on the pointer. For example, the
following code calls the Add() function:
int Add(int i, int j)
{
return i+ j;
}
int main()
{
// Create a function pointer and make it point to the Add function
int (*func)(int, int) = Add;
cout << func(23, 12) << endl; // add 23 + 12
return 0;
}
Calling a function via a function pointer is also known as an indirect function call.
The following calculator program is functionally identical to the calculator example
above, except it uses a function pointer instead of a direct function call:
#include <iostream>
using namespace std;
int Add(int i, int j)
{
return i + j;
}
int Subtract(int i, int j)
{
return i-j;
}
int Multiply(int i, int j)
{
return i *j;
}
int main()

78

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

{
int i;
cout << "Enter a number: ";
cin >> i;
int j;
cout << "Enter another number: ";
cin >> j;
int op;
do
{
cout << "Enter an operation (0=add, 1=subtract, 2=multiply): ";
cin >> op;
}
while (op < 0 ||op > 2);
// Create a function pointer named Func
int (*Func)(int, int);
// Set Func to point to the function the user chose
switch (op)
{
case 0:
Func = Add;
break;
case 1:
Func = Subtract;
break;
case 2:
Func = Multiply;
break;
}
// Call the function that Func is pointing to with i and j as parameters
cout << "The answer is: " << Func(i,j) << endl;
return 0;
}

79

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

In this example, instead of calling the Add(), Subtract(), or Multiply() function


directly, we’ve instead set Func to point at the function we wish to call. Then we
call the function through the pointer. The compiler is unable to use early binding
to resolve the function call Func(i,j) because it cannot tell which function Func will
be pointing to at compile time.

6.4. Summary
Late binding is slightly less efficient since it involves an extra level of indirection.
With early binding, the compiler can tell the CPU to jump directly to the function’s
address. With late binding, the program has to read the address held in the pointer
and then jump to that address. This involves one extra step, making it slightly
slower. However, the advantage of late binding is that it is more flexible than early
binding, because decisions about what function to call do not need to be made until
run time.

80

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

Revision Questions

Example . Explain binding in C++ language.


Solution: Binding refers to the process that is used to convert identifiers (such as
variable and function names) into machine language addresses. 

E XERCISE 21.  Differentiate static and dynamic binding


E XERCISE 22.  Discuss early binding.
E XERCISE 23.  Explain the demerits of dynamic binding.
E XERCISE 24.  Write a program code to compute the average marks for 5 stu-
dents with 7 subjects tpo explain early binding.

Problem. Using C++ program code to explain late binding.

81

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

LESSON 7
C++ Programming Operator Overloading

Learning outcomes
Upon completing this topic, you should be able to:

• Understand operators

• Understand operator loading.

• Write a program to explain operation loading

• Understand the prefix and postfix operator overloading.

82

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

7.1. Introduction to operator loading


The meaning of operators are already defined and fixed for basic types like: int,
float, double etc in C++ language. For example: If you want to add two integers
then, + operator is used. But, for user-defined types(like: objects), you can define
the meaning of operator, i.e, you can redefine the way that operator works. For
example: If there are two objects of a class that contain string as its data member,
you can use + operator to concatenate two strings. Suppose, instead of strings if
that class contains integer data member, then you can use + operator to add integers.
This feature in C++ programming that allows programmer to redefine the meaning
of operator when they operate on class objects is known as operator overloading.

7.2. Why Operator overloading is used in C++ programming?


You can write any C++ program without the knowledge of operator overloading.
But, operator operating are profoundly used by programmer to make a program
clearer. For example: you can replace the code like: calculation = add(mult(a,b),div(a,b));
with calculation = a*b+a/b; which is more readable and easy to understand.

7.3. How to overload operators in C++ programming


To overload a operator, a operator function is defined inside a class as:

Figure 1:operator Overloading.


The return type comes first which is followed by keyword operator, followed by
operator sign,i.e., the operator you want to overload like: +, <, ++ etc. and finally
the arguments is passed. Then, inside the body of you want perform the task you
want when this operator function is called. This operator function is called when,
the operator(sign) operates on the object of that class class_name.

83

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

Example of operator overloading in C++ Programming


/* Simple example to demonstrate the working of operator overloading*/
#include <iostream>
using namespace std;
class temp {
private: int count;
public: temp():count(5)
{
}
void operator ++()
{
count=count+1;
}
void Display()
{
cout<<"Count: "<<count;
}
};
int main()
{
temp t; ++t; /* operator function void operator ++() is called */
t.Display();
return 0;
}
Output
Count: 6
Explanation
In this program, a operator function void operator ++ () is defined(inside class
temp), which is invoked when ++ operator operates on the object of type temp.
This function will increase the value of count by 1.

7.4. Considerations while using Operator overloading in C++ language


1. Operator overloading cannot be used to change the way operator works on
built-in types. Operator overloading only allows to redefine the meaning of

84

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

operator for user-defined types.

2. There are two operators assignment operator(=) and address operator(&) which
does not need to be overloaded. Because these two operators are already over-
loaded in C++ library. For example: If obj1 and obj2 are two objects of same
class then, you can use codeobj1=obj2; without overloading = operator. This
code will copy the contents object ofobj2 to obj1. Similarly, you can use ad-
dress operator directly without overloading which will return the address of
object in memory.

3. Operator overloading cannot change the precedence of operators and asso-


ciativity of operators. But, if you want to change the order of evaluation,
parenthesis should be used.

4. Not all operators in C++ language can be overloaded. The operators that
cannot be overloaded in C++ are ::(scope resolution), .(member selection),
.*(member selection through pointer to function) and ?:(ternary operator).

Best practice while using operator overloading


Operator overloading allows programmer to define operator the way they want but,
there is a pitfall if operator overloading is not used properly. In above example, you
have seen ++ operator operates on object to increase the value of count by 1. But,
the value is increased by 1 because, we have used the code:
void operator ++()
{
count=count+1;
}
If the code below was used instead, then the value of count will be decreased by
100 if ++ operates on object. void operator ++()
{
count=count-100;
}
But, it does not make any sense to decrease count by 100 when ++ operator is used.
Instead of making code readable this makes code obscure and confusing. And, it
is the job of the programmer to use operator overloading properly and in consistent
manner.

85

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

Again, the above example is increase count by 1 is not complete. This program is
incomplete in sense that, you cannot use code like:
t1=++t
It is because the return type of operator function is void. It is generally better to
make operator work in similar way it works with basic types if possible. Here,
are the examples of operator overloading on different types of operators in C++
language in best possible ways: Increment ++ and Decrement – Operator Over-
loading.

7.5. Increment ++ and Decrement – Operator Overloading in C++ Program-


ming.
Increment ++ and decrements – operator are overloaded in best possible way, i.e.,
increase the value of a data member by 1 if ++ operator operates on an object and
decrease value of data member by 1 if – operator is used.

Increment Operator Overloading


/* C++ program to demonstrate the overloading of ++ operator. */
#include <iostream>
using namespace std;
class Check
{
private: int i;
public: Check(): i(0){ }
void operator ++()
{
++i;
}
void Display()
{
cout<<"i="<<i<<endl;
}
};
int main()
{

86

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

Check obj;
/* Displays the value of data member i for object obj */
obj.Display();
/* Invokes operator function void operator ++( ) */
++obj;
/* Displays the value of data member i for object obj */
obj.Display();
return 0;
}
Output
i=0
i=1
Explanation
Initially when the object obj is declared, the value of data member i for object obj is
0( constructor initializes i to 0). When ++ operator is operated on obj, operator func-
tion void operator++( ) is invoked which increases the value of data member i to 1.
This program is not complete in the sense that, you cannot used code: obj1=++obj;
It is because the return type of operator function in above program is void. Here is
the little modification of above program so that you can use code obj1=++obj.
/* C++ program to demonstrate the working of ++ operator overlading. */
#include <iostream>
using namespace std;
class Check
{
private: int i;
public: Check(): i(0){ }
Check operator ++() /* Notice, return type Check*/
{
Check temp; /* Temporary object check created */
++i; /* i increased by 1. */
temp.i=i; /* i of object temp is given same value as i */
return temp; /* Returning object temp */
}
void Display()

87

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

{
cout<<"i="<<i<<endl;
}
};
int main()
{
Check obj, obj1;
obj.Display();
obj1.Display();
obj1=++obj;
obj.Display();
obj1.Display();
return 0;
}
Output
i=0
i=0
i=1
i=1
This program is similar to above program. The only difference is that, the return
type of operator function is Check in this case which allows to use both codes ++obj;
obj1=++obj;. It is because, temp returned from operator function is stored in object
obj. Since, the return type of operator function is Check, you can also assign the
value of obj to another object. Notice that, = (assignment operator) does not need
to be overloaded because this operator is already overloaded in C++ library.

7.6. Operator Overloading of Postfix Operator


Overloading of increment operator up to this point is only true if it is used in prefix
form. This is the modification of above program to make this work both for prefix
form and postfix form.
/* C++ program to demonstrate the working of ++ operator overlading. */
#include <iostream>
using namespace std;

88

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

class Check
{
private: int i;
public: Check(): i(0)
{}
Check operator ++ ()
{
Check temp;
temp.i=++i;
return temp;
}
/* Notice int inside barcket which indicates postfix increment. */
Check operator ++ (int)
{
Check temp;
temp.i=i++;
return temp;
}
void Display()
{
cout<<"i="<<i<<endl;
}
};
int main()
{
Check obj, obj1;
obj.Display();
obj1.Display();
obj1=++obj; /* Operator function is called then only value of obj is assigned to
obj1. */
obj.Display();
obj1.Display();
obj1=obj++; /* Assigns value of obj to obj1++ then only operator function is called.
*/

89

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

obj.Display();
obj1.Display();
return 0;
}
Output
i=0
i=0
i=1
i=1
i=2
i=1
When increment operator is overloaded in prefix form; Check operator ++ () is
called but, when increment operator is overloaded in postfix form; Check operator
++ (int) is invoked. Notice, the int inside bracket. This int gives information to
the compiler that it is the postfix version of operator. Don’t confuse this int doesn’t
indicate integer.
Operator Overloading of Decrement – Operator
Decrement operator can be overloaded in similar way as increment operator. Also,
unary operators like: !, ~ etc can be overloaded in similar manner.

Example. C++ Program to Subtract Complex Number Using Operator Over-


loading

In this module, subtraction - operator is overloaded to perform subtraction of a


complex number from another complex number.
Since - is a binary operator( operator that operates on two operands ), one of the
operands should be passed as argument to the operator function and the rest process
is similar to the. Binary Operator Overloading to Subtract Complex Number /*
C++ program to demonstrate the overloading of binary operator by subtracting one
complex number from another. */
#include <iostream>
using namespace std;
class Complex
{

90

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

private:
float real;
float imag;
public:
Complex(): real(0), imag(0){ }
void input()
{
cout<<"Enter real and imaginary parts respectively: ";
cin>>real;
cin>>imag;
}
Complex operator - (Complex c2) /* Operator Function */
{
Complex temp;
temp.real=real-c2.real;
temp.imag=imag-c2.imag;
return temp;
}
void output()
{
if(imag<0)
cout<<"Output Complex number: "<<real<<imag<<"i";
else cout<<"Output Complex number: "<<real<<"+"<<imag<<"i";
}
};
int main()
{
Complex c1, c2, result;
cout<<"Enter first complex number:\n";
c1.input();
cout<<"Enter second complex number:\n";
c2.input(); /* In case of operator overloading of binary operators in C++ program-
ming, the object on right hand side of operator is always assumed as argument by
compiler. */

91

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

result=c1-c2; /* c2 is furnised as an argument to the operator function. */


result.output();
return 0;
}
Explanation
In this program, three objects of type Complex is created and user is asked to
enter the real and imaginary parts for two complex numbers which is stored in
objects c1 and c2. Then statement result=c1-c2 is executed. This statement invokes
the operator function Complex operator - (Complex c2). When result=c1-c2 is
executed, c2 is passed as argument to the operator function. In case of operator
overloading of binary operators in C++ programming, the object on right hand side
of operator is always assumed as argument by compiler. Then, this function returns
the resultant complex number(object) to main() function and then, it is displayed.

7.7. Summary
Though, this module contains the overloading of - operators, binary operators in
C++ programming like: +, *, <, += etc. can be overloaded in similar manner.
Increment ++ and decrements – operator are overloaded in best possible way, i.e.,
increase the value of a data member by 1 if ++ operator operates on an object and
decrease value of data member by 1 if – operator is used.

92

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

Revision Questions

Example . Explain why operator overloading are used in C++ program


Solution: Operator operating are profoundly used by programmer to make a pro-
gram clearer. For example: you can replace the code like: calculation = add(mult(a,b),div(a,b));
with calculation = a*b+a/b; which is more readable and easy to understand. 

E XERCISE 25.  Differentiate operator overloading and function overloading.


E XERCISE 26.  Discuss the considerations when using operator overloading
E XERCISE 27.  Write a program that uses operator overloading in C++
E XERCISE 28.  Differentiate between prefix and postfix operator overloading.

Problem. Discuss how binary operators in C++ programming like: +, *, <, += can
be overloaded.

93

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

LESSON 8
Component-Based Developments

Learning outcomes
Upon completing this topic, you should be able to:

• Understand Component-based development

• Understand Software crisis.

• How software engineering evovled

• understand emerging technlogies in Software engineering.

94

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

8.1. Introduction
This is to provide direction and guidance to C++ programmers that will enable them
to employ good programming style and proven programming practices leading to
safe, reliable, testable, and maintainable code.
C++ was designed to support data abstraction, object-oriented programming, and
generic programming while retaining compatibility with traditional C programming
techniques. Component based software engineering is the software development
model that uses different software modules and puts them together for a larger sys-
tem. Component based software engineering is based on the notion that there is a
library of first and third party certified components that developers can use to create
the desired functionality. These components are to be certified based on a standard
where developers can rely on similar assumptions about each component. This type
of model allows a reliable, flexible and fast form of software development. In to-
day’s market a quick and flexible model is beneficial to today’s changing business
needs.
One of the most promising development models is component based software en-
gineering. This model is based on the notion that developers can select appropriate
off-the-shelf software components and build them together using well defined soft-
ware architecture. Component based software engineering is concerned with the
rapid assembly of systems from components. These components and frameworks
have certified properties; which provide the basis for predicting the properties of
systems built from components. This kind of software approach is very different
from the traditional approach in which the software is built from the ground up.
Each of these commercial off-the-shelf (COTS) components can be developed by
different companies using even different languages and platforms.
If you look at Figure 1 you can see how these COTS can be taken out of a component
repository and assembled into a target software system

95

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

8.2. The Software Crisis.


In the year 1968 on a NATO conference in Garmisch Partenkirchen for the first time
the "software crisis" was mentioned. It was admitted that software development
is difficult, even so difficult that it has to be considered as an own engineering
discipline. Also, the hope aroused that a way out from the misery could be the
formation of a new software component industry and component market.
The state of software development was compared to that of many industries in the
early 19th century: the products were hand-crafted, expensive, and error prone. A
characteristic of maturing industries is that it fabricates products that are assembled
of many small standardized and exchangeable parts.
An example is electronic engineering, where small electronic components like diodes,
resistors and transistors are not designed for a single application but for numerous
and different ones. They can be composed on circuit boards to larger integrated
circuits (IC).
It was in late 1960’s and the crisis was charaterised by the following

• Many software projects failed.

• Many software projects late,

• Over budget,

• Providing unreliable software that is expensive to maintain.

• Many software projects produced software which did not satisfy the require-
ments of the customer.

• Complexities of software projects increased as hardware capability increased.

• Larger software system is more difficult and expensive to maintain.

• Demand of new software increased faster than ability to generate new soft-
ware.

• Late delivery of softwares into the market.

• Frequent changes on the user specifications.

96

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

All the above attributes of what was called a ‘Software Crisis’. So the term ‘Soft-
ware Engineering’ first introduced at a conference in late 1960’s to discuss the
software crisis.

8.3. General design


This coding standards document is intended to help programmers develop code that
conforms to safety-critical software principles, i.e., code that does not contain de-
fects that could lead to catastrophic failures resulting in significant harm to individ-
uals and/or equipment. In general, the code produced should exhibit the following
important qualities:

• Reliability: Executable code should consistently fulfill all requirements in a


predictable manner.

• Portability: Source code should be portable (i.e. not compiler or linker de-
pendent).

• Maintainability: Source code should be written in a manner that is consis-


tent, readable, simple in design, and easy to debug.

• Testability: Source code should be written to facilitate testability. Minimiz-


ing the following characteristics for each software module will facilitate a
more testable and maintainable module: 1. code size 2. complexity 3. static
path count (number of paths through a piece of code)

• Reusability: The design of reusable components is encouraged. Component


reuse can eliminate redundant development and test activities (i.e. reduce
costs).

• Extensibility: Requirements are expected to evolve over the life of a product.


Thus, a system should be developed in an extensible manner (i.e. perturba-
tions in requirements may be managed through local extensions rather than
wholesale modifications).

• Readability: Source code should be written in a manner that is easy to read,


understand and comprehend.

97

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

Remark. Note that following the guidelines contained within this module will not
guarantee the production of an error-free, safe product. However, adherence to
these guidelines, as well as the processes defined in the Software Development Plan
, will help programmers produce clean designs that minimize common sources of
mistakes and errors.

8.3.1. Coupling & Cohesion


Coupling and cohesion are properties of a system that has been decomposed into
modules. Cohesion is a measure of how well the parts in the same module fit
together. Coupling is a measure of the amount of interaction between the different
modules in a system. Thus, cohesion deals with the elements within a module (how
well-suited elements are to be part of the same module) while coupling deals with
the relationships among modules (how tightly modules are glued together).
Object-oriented design and implementation generally support desirable coupling
and cohesion characteristics. The design principles behind OO techniques lead
to data cohesion within modules. Clean interfaces between modules enable the
modules to be loosely coupled. Moreover, data encapsulation and data protection
mechanisms provide a means to help enforce the coupling and cohesion goals.
Source code should be developed as a set of modules as loosely coupled as is rea-
sonably feasible. Note that generic programming (which requires the use of tem-
plates) allows source code to be written with loose coupling and without runtime
overhead.
Examples of tightly coupled software would include the following:

• Many functions tied closely to hardware or other external software sources,


and

• Many functions accessing global data. There may be times where tightly
coupled software is unavoidable, but its use should be both minimized and
localized.

• Limit hardware and external software interfaces to a small number of func-


tions,

• Minimize the use of global data, and

• Minimize the exposure of implementation details.

98

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

8.4. What is a Component


A component is a small system itself that can fulfill one or more of the functionality
requirements for a system. A component includes the functionality that it was de-
signed for and the coordination of this small system works or how the component
will interact with the external world.
As stated previously components are COTS, which keeps the implementation of the
component hidden from the consumer. Each component is viewed as intellectual
capital that must be protected. This form of information hiding also keeps the
implementation details from being changed during development.
Software components can be viewed in two different ways: as implementation or
as architectural abstractions. When viewed as implementations the components
can be deployed and assembled in to larger systems or subsystems. When viewed
as architectural abstractions they are used to express design rules that impose a
standard coordination model that must be then followed by all components. These
design rules then take the form of a component model, and all components must
conform to this model.

8.4.1. Component Model


Component models specify the design rules that must be obeyed by the compo-
nents. These design rules are used to improve composition by removing sources
of interface mismatches, for example mismatched assumptions. These rules ensure
that the quality attributes in the system are achieved and that components can be
easily added into a system or runtime environment.
Two components can only interact if they are sharing the same assumptions and
when components follow the component model it establishes the assumptions that
those components must use.

8.4.2. Component Framework


A component framework provides the services to support and enforce a component
model. Frameworks define how components will relate with one another and how
they will work together within the system. These relationships between compo-
nents can then be reused when a similar project is developed. Compared to pat-

99

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

terns component frameworks are used to describe a larger unit of design, which
is more specialized. Another way to think of a component framework is a mini
operating system. Components in this case would be what processes are to an op-
erating system. The framework manages shared resources and provides methods of
communication among components. However unlike operating systems component
frameworks do not deal with runtime existence.

8.5. Life Cycle of Component Based Software Engineering


Component based software system are developed by selecting different components
and assembling them together rather than programming the overall system from
scratch, so the development process or life cycle is different than the traditional
software development model. The life cycle of component based software engi-
neering goes as follows:

1. Requirements analysis;

2. Software architecture selection, construction, analysis, and evaluation;

3. Component identification and customization;

4. System Integration;

5. System testing;

6. Software Maintenance

8.5.1. Requirements Analysis Phase


The requirements analysis phase of component based software engineering is much
like the traditional phase in software development. This phase in the cycle consists
of meeting with the client and discussing what functionality is required for a so-
lution to their problem. Requirements, deliverables and goals are then established
during this phase and agreed upon by you as the developer and the client. The
only difference is considering the use of software components when discussing the
requirements for the system that is going to be development.

100

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

8.5.2. Architecture Selection Phase


The software architecture selection phase involves choosing a component frame-
work that is going to be used within the system. Choosing the framework also
determines which component model that you are going to use. The choice made
during this phase will determine what components are going to be available for your
project as some components may work only in certain component models. Special
care is needed when looking at the pros and cons of these software architectures
that could possibly be used. During this phase considerations need to be made to
ensure that the software components that are needed to complete the solution are
compatible with the choice of software architecture and component framework.

8.5.3. Component Identification Phase


The third phase of component based software engineering is component identifi-
cation and customization. This is the most important part of the component based
software engineering process. There are two main parts in this step. The first being
evaluation of each candidate COTS component. The components chosen are based
on the functional and quality characteristics present for each component . Given
the large number of possible available components it is good practice to analyze
multiple components that claim to meet your functional and quality requirements.
The second part of this phase is the customization of those candidate COTS com-
ponents. The candidates should be analyzed for ease of integration and the level of
customization that the component allows. The components that are chosen in this
phase should be easily implementable from the possible customization. Once all of
the components have been analyzed and the components to use have been chosen
then the process is ready to integrate them together.

8.5.4. System Integration Phase


The fourth phase is system integration which includes making key decisions on how
to provide communication and coordination among various components of a target
software system. A system architecture design is first evaluated and selected for
the component based system. The systems architecture design should incorporate
the user’s requirements and the implementation details of the system such as plat-

101

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

form and programming languages. System architecture design should address the
advantage for selecting a particular architecture from other architectures. The sys-
tem integration process itself is the process of assembling the selected components
into the whole system based on the designed system architecture. The obvious final
objective of system integration is the final system that is composed of the selected
components. The integration process involves a few steps: initial integration, test-
ing, changing the component and reintegration (if necessary). When this phase is
completed the system should be in its final form and ready for complete system test-
ing. Also leaving this phase requires a document that will specify what is required
during the software maintenance phase.

8.5.5. Testing Phase


The fifth phase of component based software engineering is the testing phase. This
phase is the process of evaluating a system to confirm that the system satisfies the
user’s requirements and to identify and correct defects in the system implementa-
tion. The testing phase should include tests for each of the individual components
that are contained in the system architecture as well as reliability tests. For this
phase a testing strategy needs to be selected which will determine the systems tests
and the user acceptance tests. Many of the tests that will be run on the compo-
nents will be based on the documentation given by the component developers and
some things may or may not have to be tested because the component developer
may have already tested them. By the end of the system testing phase there should
be testing documentation for the testing completed that can be used during system
maintenance.

8.5.6. Maintenance Phase


The final phase of component based software engineering is of course the main-
tenance phase. The objectives of system maintenance are to provide an effective
product or service to the end users of the software system. This service includes
correcting faults, improving system performance, and adapting the system to a
changed environment. Changes that will be deemed necessary need to be docu-
mented to ensure that future changes will be able to reference past ones . Specif-

102

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

ically for software components most of the maintenance on the system will be on
the software framework or architecture designed for the system. Maintenance on
the components themselves needs to be handled by the component developer. A
support strategy for the system will reflect this and focus primarily on the services
related to communication between software components. The output of this phase
would then be a newer version of the system that can be retested based on the past
testing strategy and additional tests that may also be needed.

8.6. Current Component Technologies


There are a variety of component technologies available and each has its own advan-
tages. Current technologies include Visual Basic Controls (VBX), ActiveX Con-
trols, Java Beans, class libraries, CORBA, and COM architectures. All of these
technologies rely on underlying services to provide the communication and coordi-
nation for the application. Among the software component infrastructure technolo-
gies three have become somewhat standardized: CORBA, COM, and JavaBeans.
This is a shown in table1 below.

8.7. Summary
Component based software engineering is a very interesting and useful software de-
velopment model. It provides an easy way to assemble software using components
that have been previously developed. It offers a quick and cheap way to develop
software systems. As its popularity grows the market for already development soft-
ware components grows and offers an interesting direction for software evolution.
In order for this type of model to see success there is a great need for well de-

103

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

fined standards for components. These standards would make it possible to assume
quality for software components and make it easy for large system developers to fit
components into their software frameworks.

Revision Questions

Example . Explain the term coupling


Solution: Stack.
Scheduling properties (such as policy or priority).
Set of pending and blocked signals.
Some thread-specific data. 

E XERCISE 29.  Differentiate between a module and a component


E XERCISE 30.  Explain effects of software crisis of 1960’s
E XERCISE 31.  Discuss the advantages and disadvantages of CBSE
E XERCISE 32.  Differentiate between component model and component frame-
work.

Problem. Discuss in a group and write a report on how to ensure Quality in Com-
ponent Based Software Engineering.

104

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

LESSON 9
Introduction to Sockets Programming

Learning outcomes
Upon completing this topic, you should be able to:

• Understand sockets in computer communication.

• Differentiate threads and processes.

• Write a program codes that creates a socket.

105

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

9.1. Introduction to Sockets


A socket is the mechanism that most popular operating systems provide to give
programs access to the network. It allows messages to be sent and received between
applications (unrelated processes) on different networked machines.
The sockets mechanism has been created to be independent of any specific type of
network. IP, however, is by far the most dominant network and the most popular
use of sockets. This tutorial provides an introduction to using sockets over the IP
network (IPv4).
Sockets are a protocol independent method of creating a connection between pro-
cesses. Sockets can be either

• Connection based or connectionless: Is a connection established before com-


munication or does each packet describe the destination?

• Packet based or streams based: Are there message boundaries or is it one


stream?.

• Reliable or unreliable. Can messages be lost, duplicated, reordered, or cor-


rupted?

9.2. Socket characteristics


Socket are characterized by their domain, type and transport protocol. Common
domains are:

• AF_UNIX: address format is UNIX pathname.

• AF_INET: address format is host and port number.

Common types are:

• virtual circuit: received in order transmitted and reliably.

• datagram: arbitrary order, unreliable.

Each socket type has one or more protocols. Example.

106

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

• TCP/IP (virtual circuits)

• UDP (datagram).

Use of sockets:

• Connection–based sockets communicate client-server: the server waits for a


connection from the client.

• Connectionless sockets are peer-to-peer: each process is symmetric.

9.3. What are Threads, Ports, and how are related to Sockets?
A "thread" is a symbolic name for a connection between your computer and a re-
mote computer, and a thread is connected to a socket.
A socket can be opened on any "port"; which is simply a unique number to dis-
tinguish it from other threads, because more than just one connection can be made
on the same computer. A few of these ports have been set aside to serve a specific
purpose. Beyond these ports, there are quite a large number of other ports that can
be used for anything and everything: over 6,000, actually. A few commonly used
ports are listed below in figure 1 with their corresponding services:

Figure 1: Common ports

9.4. Working with Winsock


We need to include winsock.h and link libws2_32.a to your project in order to use
the API that are necessary for TCP/IP. If this is not possible, use LoadLibrary() to
load ws2_32.dll at runtime, or some similar method.
The first step to programming with windows sockets ( "Winsock") is starting up the
Winsock API. There are two versions of Winsock; version one is the older, limited
version; and version 2 is the latest edition and is therefore the version we prefer to
specify.

107

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

#define SCK_VERSION1 0x0101


#define SCK_VERSION2 0x0202
int PASCAL WSAStartup(WORD,LPWSADATA);
int PASCAL WSACleanup(void);
//This typedef will be filled out when the function returns
//with information about the Winsock version
typedef struct WSAData
{
WORD wVersion;
WORD wHighVersion;
char szDescription[WSADESCRIPTION_LEN+1];
char szSystemStatus[WSASYS_STATUS_LEN+1];
unsigned short iMaxSockets;
unsigned short iMaxUdpDg;
char * lpVendorInfo;
}
WSADATA;
typedef WSADATA *LPWSADATA;
Note: You should only need to call these functions once each, the former when you
initialize Winsock, and the latter when you are finished. Don’t close down Winsock
until you are finished, though, as doing so would cancel any connections that your
program has initiated or any ports that you are listening on.

9.5. Initializing a Socket


The correct parameters must be filled out and passed to a handy API call that begins
the socket (hopefully). In this case, we are returned the handle to the socket that we
have created.
Once we have finished with the program, shut down any sockets that you have
opened before your program exits. Of course, when it does, all the ties and connec-
tions it has will be forcibly shut down, including any sockets, but it’s better to shut
them down the graceful way with closesocket(). Pass the socket’s handle to this
API when you call it.
/There are many more options than the ones defined here, to see them

108

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

//browse the winsock2.h header file


#define SOCK_STREAM 1
#define SOCK_DGRAM 2
#define SOCK_RAW 3
#define AF_INET 2
#define IPPROTO_TCP 6
SOCKET PASCAL socket(int,int,int);
int PASCAL closesocket(SOCKET);
When creating a socket, you will need to pass the "address family", socket "type",
and the "protocol type"
Pass AF_INET as the default address family. This parameter specifies how the
computer addresses will be interpreted.
There is more than just one type of socket; actually, there are many more. Three
of the most common ones include: Raw Sockets, Stream Sockets, and Datagram
Sockets. Stream sockets, however, are what we are using in this tutorial, since we
are dealing with TCP protocols, so we will specify SOCK_STREAM as the second
parameter to socket().

9.5.1. Connecting to a Remote Host (Acting as the Client)


Fill out information about the remote host that you are connecting to, and then pass
a pointer to this structure to the magic function, connect(). This structure and the
API are listed below. Note that the sin_zero parameter is unneeded and is thus left
blank.
struct sockaddr_in
{
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
int PASCAL connect(SOCKET,const struct sockaddr*,int);
Complete code.
//CONNECT TO REMOTE HOST (CLIENT APPLICATION)

109

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

//Include the needed header files.


//Don’t forget to link libws2_32.a to your program as well
#include <winsock.h>
SOCKET s; //Socket handle
//CONNECTTOHOST – Connects to a remote host
bool ConnectToHost(int PortNo, char* IPAddress)
{
//Start up Winsock. . .
WSADATA wsadata;
int error = WSAStartup(0x0202, &wsadata);
//Did something happen?
if (error)
return false;
//Did we get the right Winsock version?
If (wssadata.wVersion != 0x0202)
{
WSACleanup();//Clean up Winsock
return false;
}
//Fill out the information needed to initialize a socket. . .
SOCKADDR_IN target; //Socket address information
target.sin_family = AF_INET; // address family Internet
target.sin_port = htons (PortNo); //Port to connect on
target.sin_addr.s_addr = inet_addr (IPAddress); //Target IP
s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); //Create socket
if (s == INVALID_SOCKET)
{
return false; //Couldn’t create the socket
}
//Try connecting...
if (connect(s, (SOCKADDR *)&target, sizeof(target)) == SOCKET_ERROR)
{
return false; //Couldn’t connect
}

110

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

else
return true; //Success
}
//CLOSECONNECTION – shuts down the socket and closes any connection on it
void CloseConnection ()
{
//Close the socket if it exists if (s) closesocket(s);
WSACleanup(); //Clean up Winsock
}
Receiving Connections – Acting as a Server
This code explain how to play the "server" role; so as remote computers can connect
to it. The server can "listen" on any port and await an incoming connection as usual.
int PASCAL bind(SOCKET,const struct sockaddr*,int); //bind to a socket
int PASCAL listen(SOCKET,int); //Listen for an incoming connection
//Accept a connection request
SOCKET PASCAL accept(SOCKET,struct sockaddr*,int*);
an receive requests for a connection on the port you are listening on: say, for ex-
ample, a remote computer wants to chat with your computer, it will first ask your
server whether or not it wants to establish a connection. In order for a connection to
be made, your server must accept() the connection request. Note that the "server"
decides whether or not to establish the connection. Finally, both computers are
connected and can exchange data.
Although the listen() function is the easiest way to listen on a port and act as the
server, it is not the most desirable. You will quickly find out when you attempt it
that your program will freeze until an incoming connection is made, because listen()
is a "blocking" function – it can only perform one task at a time, and will not return
until a connection is pending.
Before communication- listening on a port is accomplished, you must:

1. Initialize Winsock

2. Start up a socket and make sure it returns a nonzero value, which signifies
success and is the handle to the socket

3. Fill out the SOCKADDR_IN structure with the necessary data, including the
address family, port, and IP address.

111

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

4. Use bind() to bind the socket to a specific IP address (if you specified inet_addr("0.0.0.0")
or htonl(INADDR_ANY) as the sin_addr section of SOCKADDR_IN, you
can bind to any IP address)

The first parameter of listen() must be the handle to a socket,You can then specify,
with the next and final parameter, how many remote computers can communicate
with your server at the same time. Generally, however, unless you want to exclude
all but one or a few connections, we just pass SOMAXCONN (SOcket MAX CON-
Nection) as the final parameter to listen(). If the socket is up and working fine, all
should go well, and when a connection request received, listen() will return. This is
your clue to call accept(), if you wish to establish a connection.
#include <windows.h>
#include <winsock.h>
SOCKET s; WSADATA w;
//LISTENONPORT – Listens on a specified port for incoming connections //or data
int ListenOnPort(int portno)
{
int error = WSAStartup (0x0202, &w); // Fill in WSA info
if (error)
{
return false; //For some reason we couldn’t start Winsock
}
if (w.wVersion != 0x0202) //Wrong Winsock version?
{
WSACleanup ();
return false;
}
SOCKADDR_IN addr; // The address structure for a TCP socket
addr.sin_family = AF_INET; // Address family
addr.sin_port = htons (portno); // Assign port to this socket
//Accept a connection from any IP using INADDR_ANY
//You could pass inet_addr("0.0.0.0") instead to accomplish the
//same thing. If you want only to watch for a connection from a /
/specific IP, specify that //instead.
addr.sin_addr.s_addr = htonl (INADDR_ANY);

112

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); // Create socket


if (s == INVALID_SOCKET)
{
return false; //Don’t continue if we couldn’t create a //socket!!
}
if (bind(s, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR)
{
//We couldn’t bind (this will happen if you try to bind to the same //socket more
than once)
return false;
}
//Now we can start listening (allowing as many connections as possible to
//be made at the same time using SOMAXCONN). You could specify any
//integer value equal to or lesser than SOMAXCONN instead for custom
//purposes). The function will not //return until a connection request is //made
listen(s, SOMAXCONN);
//Don’t forget to clean up with CloseConnection()!
}
If you compile and run this code, your program will wait until a connection request
is made. You could cause this connection request by, for example, trying a "telnet"
connection. The connection will inevitably fail, or course, because the connection
will not be accepted, but you will cause listen() to return and your program will
resurrect from the land of the dead
You can try this by typing telnet 127.0.0.1 "port_number" at the MSDOS command
prompt (replace "port_number" with the port that your server is listening on).

9.6. Summary
A socket is the mechanism that most popular operating systems provide to give
programs access to the network. It allows messages to be sent and received be-
tween applications (unrelated processes) on different networked machines.Socket
are characterized by their domain, type and transport protocol. Common domains
are:

113

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

• AF_UNIX: address format is UNIX pathname.

• AF_INET: address format is host and port number.

Common types are:

• virtual circuit: received in order transmitted and reliably.

• datagram: arbitrary order, unreliable.

For the environment for the socket to work, we need to include winsock.h and link
libws2_32.a to your project in order to use the API that are necessary for TCP/IP.
If this is not possible, use LoadLibrary() to load ws2_32.dll at runtime, or some
similar method.

Revision Questions

Example . Explain the concept of socket programming.


Solution: A socket is the mechanism that most popular operating systems provide
to give programs access to the network. It allows messages to be sent and received
between applications (unrelated processes) on different networked machines.


E XERCISE 33.  Explain how to initilize a socket in C++.


E XERCISE 34.  Discuss the characteristics of a socket. and how is it different
from a thread.
E XERCISE 35.  Write a small program code to explain how to connect to a Re-
mote Host (Acting as the Client)
E XERCISE 36.  Write a program code in C++ to demonstrate how to receive
Connections while a machine acts as Server.

Problem. Discuss the asynchronous Socketsin C++.

114

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

LESSON 10
Remove Method Invocation in C++

Learning outcomes
Upon completing this topic, you should be able to:

• Understand threads and Processes

• Create Threads and Processes.

• Differentiate threads and processes.

• Write threads and processes in C++.

115

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

10.1. Introduction to Remote Method Invocation.


Distributed systems require that computations running in different address spaces,
potentially on different hosts, are able to communicate. "Raw" communications via
sockets require applications to engage in application-level protocols to encode and
decode messages. The design of such protocols is cumbersome and time consum-
ing. RPC (Remote Procedure Call) abstracts the communication interface to the
level of a procedure call. RPC, however, does not translate well into distributed
object systems, where communications are needed between program-level objects
in different address spaces. To match the semantics of object invocation, distributed
object systems require RMI (Remote Method Invocation). RMI provides the ability
to call a method on a remote object using the same syntax as for a local object. It
essentially allows objects residing on another machine to be treated like they are
almost local to your machine.
The mainly mechanism for making distributed function calls between C++ pro-
grams is to use CORBA(Common Object Request Broker Architecture), but for
many applications, it becomes complicated. The CORBA specifications allow dis-
tributed function calls to be made between code written in any number of languages,
and to make it all work, specialized tools need to be integrated into the build pro-
cess, in order to translate object definitions written in CORBA’s IDL(Interface Def-
inition Language) to whichever native language is being used (C++, Java, etc.).
However, if we assume that the server and client are both written in the same lan-
guage, let us assume C++, since it is possible to do away with these complexities.
In particular, instead of elaborate definitions of interfaces and marshalling specifi-
cations, we can simply defer to C++.
Instead of separate IDL files with object interfaces, we specify the interfaces di-
rectly in C++ source code, using the preprocessor, and to marshal arguments across
process boundaries, we use the native C++ serialization framework.

10.1.1. A Simple Example


As an example, a simple echo server looks like this:
#include <RCF/RCF.hpp>
RCF_BEGIN(I_Echo, "I_Echo")
RCF_METHOD_R1(std::string, echo, const std::string &);
RCF_END(I_Echo);

116

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

class Echo
{
public:
std::string echo(const std::string &msg) { return msg; }
};
int main()
{
int port = 50001;
RCF::RcfServer server(port);
server.bind<I_Echo, Echo>();
server.start();
return 0;
}
And the client:
#include <RCF/RCF.hpp>
RCF_BEGIN(I_Echo, "I_Echo")
RCF_METHOD_R1(std::string, echo, const std::string &);
RCF_END(I_Echo);
int main()
{
std::cout << RcfClient<I_Echo>("localhost", 50001).echo("my message");
return 0;
}
The Boost.Serialization library is used to serialize parameters and return values.
It handles standard types and containers automatically, and is easily extended to
user defined classes. It also allows us to serialize pointers, with proper handling of
polymorphic pointers and multiple pointers to single objects. Basic Usage There
are three basic steps to using this framework:

10.2. Basic Usage


There are three basic steps to using this framework:

1. Use the RCF_xxx macros to define interfaces.

2. Use the RcfServer class to expose objects that implement the interface.

117

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

3. Use the RcfClient<> classes to invoke methods on the objects exposed by the
server. The interface definition macros are used as follows:

RCF_BEGIN( type, type_id )


// ...
RCF_METHOD_xx( return_type, name, ....):
// ...
RCF_END( type )
type is the identifier for the interface, type_id is a string giving a runtime description
of the interface.
The RCF_METHOD_xx macros define the member functions, and are named ac-
cording to the number of arguments and whether the return value is void or not.
So, for a function func accepting two strings and returning an integer, we write:
RCF_METHOD_R2(int, func, std::string, std::string);
and if the function has a void return type, we would instead write:
RCF_METHOD_V2(void, func, std::string, std::string);
Dispatch IDs for each function are generated automatically; the first member func-
tion is numbered 0, the next one 1, and so on.
So, the order in which the functions appear in the definition is important, unlike in
CORBA, where dispatch IDs are based on the function name.
The dispatch IDs are generated using templates and not any preprocessor __LINE__
trickery, so the interface does not change if blank lines are inserted. The maxi-
mum number of member functions that can appear between RCF_BEGIN() and
RCF_END() is at the moment limited to 25, but this limit is arbitrary. The purpose
of the RCF_xxx macros is to define the class RcfClient<type>. This class serves
as a client stub, from the user’s point of view, but also has facilities that allow the
framework to use it as a server stub.
These macros can be used in any namespace, not just the global namespace. Once
we have defined an interface using the RCF_xxx macros, we can start a server and
bind the interface to concrete objects:
{ // create the server and tell it which port to listen on
RCF::RcfServer server(port);
// Interface is the identifer of the interface we’re exporting,
// Object is a type that implements that interface
// one object for each client

118

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

server.bind<Interface, Object>();
// ... or one object shared by all clients
Object object; server.bind<Interface>(object);
// tell the server to start listening for connections
server.start();
// ...
// the server will shut down automatically as it goes out of scope
}
The objects are statically bound to the corresponding interface; there is no need for
the object to derive from an interface class as is the case for traditional dynamic
polymorphism. Instead, the compiler resolves the interface at compile time, which
is not only more efficient, but also allows more flexible semantics.
The server can handle multiple simultaneous clients, even in single threaded mode,
and can be stopped at any time. The lifetime of objects exposed by the server is
determined by the number of current connections to the given object; once there
are no more live connections to the object, a timeout is set, and when it expires, the
object is deleted.
To make a client call, we instantiate the corresponding RcfClient<> template and
pass the server IP and port number to the constructor. When the first remote method
is called, the client then attempts to connect to the server, queries for the given ob-
ject, invokes the requested member function of the remote object, and then returns
the remote return value.
// define the interface
RCF_BEGIN(Interface, "Interface")
RCF_METHOD_R2(int, add, int, int);
RCF_END(Interface);
// ...
{ std::string ip = "localhost";
int port = 50001;
RcfClient<Interface> client(ip, port); // connect and call the add function
int sum = client.add(1,1); // connection closed as we exit scope
}
Should any exceptions arise on the server side while invoking the requested object,
an exception of type RCF::RemoteException will be propagated back to the client

119

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

and thrown.
Should any exceptions arise anywhere else on the server side, e.g., while serializing
arguments, then the server will forcibly close the connection, and the client will
throw an exception.
RCF will automatically handle a range of parameter types, including C++ primitive
types (int, double, etc.), std::string, STL containers, and pointers and references to
any of the previously mentioned types. Polymorphic pointers and references, and
multiple pointers to single objects are correctly handled as well.
Smart pointers are also supported (boost::shared_ptr, std::auto_ptr), and are the
safest way of passing polymorphic parameters.
In CORBA, one can tag a parameter as in, out, or inout, depending on which
direction(s) one wants the parameter to be marshaled.
In RCF, the marshaling directions are deduced from the parameter type, according
to the following conventions:
value:in
Pointer: in
Const reference: in
Nonconst reference: inout
Nonconst reference to pointer: out
To use user-defined types as parameters or return values, some additional serializa-
tion code is needed. What that code is depends on which serialization protocols
are being used; by default Boost.Serialization is used, and an example of passing a
user-defined type would look like the following:
struct MyStruct
{
int a;
int b;
int c;
double d;
std::string s; std::map <std::string, std::vector<std::string> > m;
template<typename Archive>
void serialize(Archive &archive, unsigned int version) { ar & a & b & c & d & s &
m; } };
RCF_BEGIN(MyInterface, "MyInterface")

120

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

RCF_METHOD_R1(MyStruct, myfunc, const MyStruct &);


RCF_END(MyInterface);

10.3. Implementing RMI for C++ Objects


RMI (Remote Method Invocation) provides the ability to call a method on a remote
object using the same syntax used for a local object. This article describes how to
access remote C++ objects using RMI.
To accomplish the RMI access mechanism for remote C++ objects. This technique
is not limited to communications between applications written in C++. It is equally
effective for implementing RMI access to remote C++ objects from clients written
in, say, Java.
10.3.1. Design
The basic idea behind RMI is fairly straightforward and well developed. It is a
classic case of the Remote Proxy pattern
The idea is to provide a local proxy object through which all communications with
the actual remote object will be channeled. The main responsibilities of such a
proxy are:

• Providing an interface identical to the real object.

• Controlling creation, access to, and destruction of the real object.

• Encoding requests to and decoding replies from the real object.

This is an example on how to do that.


// Original classes.
class Widget
{
public:
virtual ~Widget();
Widget(const std::string& name);
private: ...
};

121

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

class Circle : public Widget


{ public:
~Circle();
Circle(const std::string& name, const Point& center, int radius);
private: ...
};
// Client-based proxy classes
// generated in rmi_widget.h and
// rmi_circle.h declaration files.
namespace RMI
{
struct Widget : public RMIB
{
~Widget();
Widget(const std::string& name);
Widget(const Widget&);
Widget& operator=(const Widget&);
// RMI support ctor.
Widget(const Call& c) : RMIB(c) {} };
struct Circle : public Widget {
// No dtor needed.
Circle(const std::string& name, const Point& center, int radius);
Circle(const Circle&);
Circle& operator=(const Circle&); // RMI support ctor.
Circle(const Call& c) : Widget(c) {}
};
} // End of RMI namespace.
The code fragment above shows two stripped-down classes and the corresponding
RMI proxies generated for them. Proxies are essentially interface classes.
Generated proxy declarations can be used to write the following code on the client:
// Include proxy declarations.
#include <rmi_widget.h>
#include <rmi_circle.h>
using namespace RMI;

122

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

int main()
{ ... // Connect to the server.
RMI::connect(...);
...
Point center(11, 22); // A RMI::Circle proxy (not the real // Circle object) is created
on the // client.
Circle circle("Circle", center, 33);
}
. The RMI::Circle proxy constructor communicates with the server, which in turn
remotely creates a Circle instance and returns an RMI reference to the instance.
When the circle proxy goes out of scope, it destroys the remote Circle object that it
created and represented.
The necessary steps for building an RMI-enabled distributed system are essentially
very similar to those required by the Java RMI. as follows.

1. Write Widget and Circle classes.

2. Run these classes through the RMI code generator to generate declarations
for corresponding RMI::Widget and RMI::Circle proxies and the necessary
client/server infrastructure.

3. Compile generated server code.

4. Write and compile the client application using generated RMI proxies.

5. Run the system.

The Java concept of dynamic class loading from the server is not supported. Un-
like Java (a programming environment), C++ (a programming language) does not
specify bytecode formats. That makes implementation of such a feature unrealistic.

10.4. Extending the Interface


class Widget { ... const std::string& name() const;
};
class Circle : public Widget
{
...

123

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

const Point& center() const;


void center(const Point&);
};
namespace RMI
{
struct Widget : public RMIB
{
...
std::string name() const;
};
struct Circle : public Widget
{
...
Point center() const;
void center(const Point&);
};
} // End of RMI namespace.
Given the interface, writing the client code to create, access, and delete remote
objects is hardly different than using real Circle instances locally:
using namespace RMI;
using std::string;
int main()
{
...
Point center(23, 46);
Circle circle("Circle", center, 44);
string name = circle.name();
circle.center(Point(33, 44));
}
Note that unlike their real counterparts proxy member functions do not return ref-
erences or pointers (in a C++ sense). It is hardly surprising. All the data resides
on the server. There is nothing in the client address space to which the proxy can
return a reference or pointer. Therefore, return values from remote methods are

124

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

returned (and arguments to remote methods are passed internally) by an RMI ref-
erence (proxy) or by value, using object serialization. Any data of any type can be
passed to or from a remote method as long as the data is a registered remote object
(having an RMI proxy generated for it), or a serializable object (having conversion
functions implemented for the type).

10.5. Adding User defined Types


From the Point class, if Point instances are being created locally or remotely then
there is the remarkable degree of transparency provided by the RMI infrastructure.
However, for the code to compile, Point needs to be integrated into your distributed
environment. In order to do that, you need to decide if Point instances are to be
created in one of the two following ways:

1. Remotely (on the server) and returned or passed by an RMI reference.

2. Locally (on the client or the server) and, therefore, returned or passed by
value. For the first option, you’ll need to generate an RMI::Point proxy in
the same way we did for Widget and Circle: // The original class

class Point { ...


Point(int x, int y); ... int x_; int y_; };
// Generated RMI proxy
namespace RMI {
struct Point : public RMIB
{
~Point();
Point(int x, int y);
Point(const Point&);
Point operator=(const Point&);
// RMI support ctor.
Point(const Call& c) : RMIB(c) {} };
} // End of RMI namespace.
This is trivial. However, this approach is likely to be somewhat inefficient for small
or transient objects. Consider:

125

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

{
...
RMI::Point center(23,46);
RMI::Circle* circle = new RMI::Circle("new", center, 33);
}
This fragment will result in the following message exchange between the client and
the server:

1. The client creates an RMI::Point proxy and sends a request to create a remote
Point object.

2. The server sends the reply with the reference to the new Point object.

3. The client sends a request to create a remote Circle object passing the RMI::Point
reference as an argument.

4. The server sends the reply with the reference to the new Circle object.

5. The client sends a request to delete the remote Point object when center goes
out of scope.

6. The server sends the confirmation of successful deletion. This is quite a "con-
versation" for just two lines of code.

More so, for every proxy on the client, there is a real object on the server allocated
using operator new. Remotely allocating and destroying a small and transient Point
object is likely to be unnecessarily expensive performance-wise and resource-wise.
If creating Point objects locally and simply passing them by value.
{
...
Point center(23, 46);
RMI::Circle* circle = new RMI::Circle("new", center, 33);
}
The use of full type qualifications is to highlight a subtle change.
A Point instance is created instead of an RMI::Point proxy. The client-server dialog
shrinks considerably:

126

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

1. The client sends a request to create a remote Circle object passing a locally
created Point object by value as an argument.

2. The client receives the reply with the reference to the new Circle object.

This approach requires the Point class to be serializable.


Object serialization is the process of converting a complete object from the memory-
based format into a format better suited for storing the object on disk, sending it over
the network, etc.
In the context of the discussed RMI infrastructure, the serialization requirement
translates into having a pair of conversion routines for the Point type:
namespace RMI { string convert(const Point& point)
{
ostringstream stream;
stream << point.x()
<< " "
<< point.y();
return stream.str();
}
template<>
Point
convert<Point>(const string& str)
{
int x, y;
istringstream stream(str);
stream >> x >> y;
return Point(x, y);
}
} The RMI infrastructure already provides serialization routines for some classes
and primitive types (int, double, std::string, etc.).

10.6. Summary
The RMI namespace is open — add serialization routines for more types when the
need arises. Java RMI uses a technology called object serialization to transform an
object into a linear format. That technology essentially flattens an object and any

127

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

objects it references. An object can be simple and self-contained or it can refer to


other objects in complex graph-like (or even cyclical graph) structures. In general
terms, serializing an object is not a trivial task. Unlike Java, C++ does not address
the issue, and you’ll have to integrate libraries, taking care of serialization if you
want to use it extensively. A safer approach would be to limit the use of serialization
and rely on passing objects by an RMI reference. This sensible approach is favored
by Java RMI and the "remote object" parameter type.

Revision Questions

Example . Explain the concept of RMI in C++


Solution: RMI provides the ability to call a method on a remote object using the
same syntax as for a local object. It essentially allows objects residing on another
machine to be treated like they are almost local to your machine. 

E XERCISE 37.  Discuss using a diagram how RMI works in C++ language.
E XERCISE 38.  Explain the message exchange between the client and the server
in a RMI environment. .
E XERCISE 39.  Write a simple program code to explain RMI in C++
E XERCISE 40.  Compare the implementation of RMI in C++ and in Java lan-
guage.

Problem. Write a simple program code that uses a RMI mechanism with a user
defined type.

128

Downloaded by ERIC BARASA ([email protected])


lOMoARcPSD|19695326

BIT 2203 Advanced Programming

Solutions to Exercises
Exercise 2. this is the answer to the SECOND question Exercise 2
Exercise 6. this is the answer to the SECOND question Exercise 6
Exercise 10. this is the answer to the SECOND question Exercise 10
Exercise 26. this is the answer to the SECOND question Exercise 26
Exercise 30. this is the answer to the SECOND question Exercise 30
Exercise 34. this is the answer to the SECOND question Exercise 34
Exercise 37. this is the answer to the SECOND question Exercise 37

129

Downloaded by ERIC BARASA ([email protected])

You might also like