Advanced C++ Programming Advanced C++ Programming
Advanced C++ Programming Advanced C++ Programming
Advanced C++ Programming Advanced C++ Programming
C++ Programming
Introduction
Introduction
The goal of this course is to provide insight into the
advanced features and its internal working
To enable the participants to develop good object
oriented design and use C++ effectively.
Prerequisites
A working knowledge of C++ and some basic
object-oriented concepts.
What is a pointer ?
What is a class ?
What is inheritance ?
Outline
Module 1: Basic structure of C++ program
Module 2: Namespace
Module 3: Functions
Module 4: Object Model
Module 5: Initialization & Clean up
Module 6: Dynamic Memory Management
Module 7: Inheritance & Containment
Module 8: Templates and Generic programming
Module 9: Exception Handling
MODULE 1
Preprocessed
code
C++ compiler
Object code
Other object
files/modules
C++ linker
Library files
Executable
code- .EXE
env
argv
argc
Auto variables for main
STACK
Library functions if
dynamically linked
(.SO , .DLL)
Shared Memory
HEAP
(malloc/realloc arena)
Initialized and
unintialized data
DATA Segment
CODE/TEXT Segment
.bss
BSS stands for Block Started by Symbol.
It holds un-initialized global and static variables.
Since the BSS only holds variables that don't have any values yet, it
doesn't actually need to store the image of these variables.
.data
Contains the initialized global and static variables and their values.
It is usually the largest part of the executable. It usually has
READ/WRITE permissions.
.rdata
Also known as .rodata (read-only data) section.
This contains constants and string literals.
Symbol table
A symbol is basically a name and an address.
Symbol table holds information needed to locate and relocate a
programs symbolic definitions and references.
A symbol table index is a subscript into this array.
Index 0 designates both the first entry in the table and serves as
the undefined symbol index.
The symbol table contains an array of symbol entries.
Why OO technology?
Dependency Management
It is rigid
It is fragile
It is not reusable
It has high viscosity
It is Rigid
Rigidity is the inability to be changed
It is Fragile
Software changes seem to exhibit non-local effects
Quality is unpredictable.
The development team loses credibility
Increasing Risk
Probability of
introducing a bug
1.0
Changes
It is not reusable
More Flexible
Less fragile,
the bugs are boxed
in
Easier to reuse
Easier to make the right change
MODULE 2
Namespaces
Namespace pollution
Namespaces (contd..)
Scope for enclosing otherwise global declarations
namespace Mine
{
void print(int);
const float pi = 3.1415925635;
class Shape { };
}
void bar(float y)
{
float x = y + Mine::pi;
Mine::print(5);
}
Namespaces (contd..)
using directive brings namespaces or objects into scope
namespace Mine
{
const float pi = 3.1415926535;
void print(int);
}
using Mine::print;
void foo() { print(5); } // invoke
Mine::print
using namespace Mine;
float twopi = 2*pi;
// Mine::pi
Namespaces (contd..)
Namespaces are open: declarations can be added
namespace Mine
{
void f(int);
}
namespace Mine
{
void g(int);
}
Namespaces (contd..)
Declarations and definitions can be separated
namespace Mine
{
void f(int);
}
void Mine::f(int a)
{
/* */
}
MODULE 3
Function stack
One of the most important mechanisms a programmer
should understand is the function call stack (sometimes
referred to as the program execution stack).
Function stack
This entry, called a stack frame or an activation record, contains the
return
address that the called function needs to return to the calling
function.
Of course, the amount of memory in a computer is finite, so only a
certain
amount of memory can be used to store activation records on
the function call stack.
If more function calls occur than can have their activation records
stored
on the function call stack, an error known as stack overflow
occurs.
CALLING CONVENTIONS
What Are Calling Conventions?
C++ provides a way of defining a function and a way of calling that
function with arguments that soon become second nature to use.
the function and calls to it are compiled there are quite a
fewWhen
different ways in which the process of getting those
arguments to where the functions code can see them before
executing the code can be performed.
There are pros and cons to each, and some compilers have
extensions
which allow you to choose which is used.
of the time there is no need to do anything other than use
theMost
defaults or, in a few cases where you are required to match a
binary specification, do what you are told.
But you might want to make use of this in some cases, or simply
understand what it is going on with calling conventions used by
code you interface with.
__cdecl
__stdcall
__fastcall
__thiscall
GCC Compiler:
void fun(); ------- void fun() __attribute((cdecl))__ ;
Linkage Specification
This is to tell the compiler that the following function is
not defined in this program, and it is the compiler's job to
look for the definition.
This is also to inform the compiler that the following
function was compiled as C code.
C++ specially encodes method names for type-safe
linkage, but C doesnt.
So when an attempt is made to link C code with C++
code, the method compiled in C will not be directly
recognized.
For a single method:
extern C method prototype
Inline Functions
Function calls
Cause execution-time overhead
Qualifier inline before function return type "advises" a
function to be inlined
Puts copy of function's code in place of function call
FUNCTION POINTER
&
CALLBACKS
FUNCTION POINTER
Function Pointers provide some extremely interesting,
efficient and elegant programming techniques.
You can use them to replace switch/if-statements, to
realize your own late-binding or to implement callbacks.
Unfortunately -probably due to their complicated syntax they are treated quite step motherly in most computer
books and documentations. If at all, they are addressed
quite briefly and superficially.
They are less error prone than normal pointers because
you will never allocate or deallocate memory with them. All
you've got to do is to understand what they are and to
learn their syntax. But keep in mind: Always ask yourself if
you really need a function pointer.
GNU GCC
Function Overloading
Function overloading:
Functions with same name and different parameters
Overloaded functions should perform similar tasks
Function to square ints and function to square floats
y; }
integer 7 is 49
The square of double 7.5 is 56.25
Function Templates
Function templates
int x;
int y = square(x);
If int parameter, all T's become ints
Can use float, double, long...
// An example on
// Using a function template
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
template < class T >
T maximum( T value1, T value2, T value3 )
{
T max = value1;
if ( value2 > max )
max = value2;
if ( value3 > max )
max = value3;
}
return max;
int main()
{
int int1, int2, int3;
cout << "Input three integer values: ";
cin >> int1 >> int2 >> int3;
cout << "The maximum integer value is: "
<< maximum( int1, int2, int3 );
// int version
Input three
The maximum
Input three
The maximum
Input three
The maximum
// char version
integer values: 1 2 3
integer value is: 3
double values: 3.3 2.2 1.1
double value is: 3.3
characters: A C B
character value is: C
MODULE 4
OBJECT MODEL
int CA::a
int CA::b
void CA::fun1(){ }
CA obj;
void CA::fun2(){ }
int CA::a
int CA::b
Member Data table
CA obj;
& void CA::fun1(){ }
Member function table
(holds addresses)
int CA::a
This pointer
int CA::b
CA obj;
void CA::fun1(){ }
void CA::fun2(){ }
Class internals
Every member function of a class has an hidden formal
parameter called the this pointer.
The hidden formal parameter is designed to hold the
address of the object which was responsible for calling
that member function.
The compiler translates the code into a more detailed form as
illustrated in the subsequent slide. Consider the following piece of
code.
class CA
{
private:
int a,b;
public:
CA();
CA(int);
CA(int,int);
~CA();
void print() const;
};
Class internals
CA::CA(){ .. }
CA::CA(int x){ .. }
CA::CA(int x, int y){..}
CA::~CA(){ .. }
void CA::print() const {..}
main()
{
CA obj1;
CA obj2(200);
CA obj3(30,40);
//.....
obj1.print();
obj3.CA::~CA();
obj2.CA::~CA();
obj1.CA::~CA();
}
CA
Base
class
class CA
{
//.
Derived
class
CB
};
class CB: public CA
{
//
};
Multi-level Inheritance
class CA
CA
{
//.
};
CB
CC
};
class CC: public CB
{
CD
//
};
class CD: public CC
{
//
};
One-to-many Inheritance
class CA
{
//.
};
CA
CB
CC
CD
//
};
class CC: public CA
{
//
};
class CD: public CA
{
//
};
Multiple Inheritance
class CA
{
//.
CA
CB
CC
};
class CB
{
//
CD
};
class CC
{
//
};
class CD: public CA,public CB, public CC
{
//
};
CA
CB
};
CC
CD
class CB:public CA
{
//
};
class CC:public CA
{
//
};
class CD: public CB, public CC
{
//
};
Object Layout
class CA
//BASE CLASS
CA::a
CA::b
private:
int a,b;
CA OBJECT
LAYOUT
public:
//...
};
CA::a
class CB:public CA
CLASS
{
private:
int a,b;
//DERIVED
CA::b
CB::a
CB::b
public:
//....
};
CB OBJECT
LAYOUT
Sub object
Static Members
static
Employee::count
Employee::getCount()
Operator Overloading
Introduction (II)
Operator overloading
Use traditional operators with user-defined objects
Straightforward and natural way to extend C++
Requires great care
When overloading misused, program difficult to understand
Format
Write function definition as normal
Function name is keyword operator followed by the symbol
for the operator being overloaded.
operator+ would be used to overload the addition operator
(+)
Built-in types
Cannot overload operators
You cannot change how two integers are added
Operator functions
Can be member or non-member functions
HugeInteger bigInteger;
int integer;
bigInteger = integer + bigInteger;
or
bigInteger = biginteger + integer;
Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//An example on
// Overloading the stream-insertion and
// stream-extraction operators.
#include <iostream>
using
using
using
using
using
std::cout;
std::cin;
std::endl;
std::ostream;
std::istream;
#include <iomanip>
using std::setw;
class PhoneNumber {
friend ostream &operator<<( ostream&, const PhoneNumber & );
friend istream &operator>>( istream&, PhoneNumber & );
private:
char areaCode[ 4 ];
char exchange[ 4 ];
char line[ 5 ];
};
Example (contd..)
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
Program Output
OUTPUT:
Enter phone number in the form
(123) 456-7890:
(800) 555-1212
The phone number entered was:
(800) 555-1212
class String
{
public:
bool operator!() const;
...
};
y += z;
equivalent to
operator+=(y,z);
cout << s;
Can be overloaded
How does the compiler distinguish between the two?
Prefix versions overloaded same as any other prefix unary
operator would be. i.e. d1.operator++(); for ++d1;
Postfix versions
When compiler sees postincrementing expression, such as
d1++;
Generates the member-function call
d1.operator++( 0 );
Prototype:
Date::operator++( int );
MODULE 5
Constructor
A constructor is a special method or member function
of a class, incidentally taking the name of the class as
the method name.
It is a method that does not return any value or has
any return type associated with it.
This method may or may not take any formal
parameters. That is it can be overloaded if desired.
This method is called constructor for the reason, It
would get implicitly invoked by an object at the time of
its construction hence the name CONSTRUCTOR.
Constructor (contd..)
Destructor
A destructor is a special method or member function
of a class taking the name of the class as its method
name only prefixed with a ~ tilde symbol.
This method does not return any value or has any
return type associated with it.
This method does take any known formal parameters
either. That is it cannot be overloaded.
This method is called destructor for the reason, it
would get implicitly invoked by an object at the time of
objects destruction hence the name DESTRUCTOR.
Destructor (contd..)
If there is any clean-up job a programmer wishes to
accomplish at the time of the objects destruction, then
such business can be employed inside this method.
Note:
It is not compulsory to have constructor or destructor methods in a class.
These methods are need based.
At the same time it does not mean that if a class has constructor
method(s) we should also have destructor method.
The compiler does not assume a default constructor or destructor
method unless and until we provide one.
There are certain specific scenarios where a compiler would assume
default constructor and destructor methods. These scenarios are
highlighted in the slides to follow.
Case 3:
When a class CD multiple inherits virtually. Default
constructors for class CB,CC & CD would be
automatically assumed by the compiler.
class CA {. };
class CB: virtual public CA {. };
class CC: virtual public CA {};
class CD :public CB, public CC {};
Initializer list
One of the primary jobs a programmer would wish to use
the constructor for is to initialize the object at the time of
its construction.
Consider the following class.
class rectangle
{
private:
int base, height;
public:
//constructor placing values in objects data
rectangle(int x=0, int y=0)
{
base=x;
height=y;
}
};
//initialization
//list
{
// base=x;
// height=y;
}
};
CB obj1
CB obj2
CA *p
&&
CA *p
&&
S
T
A
C
K
CB obj1(10,20);
CB obj2(30,40);
CA::a 10
CA::b 20
CA::a 30
CA::b 40
CA
CA
H
E
A
P
Shallow Copy
CB obj1
CA *p
&&
CB obj2
Shallow
copy
CA *p
&&
S
T
A
C
K
CB obj2(obj1);
compiler synthesized
copy constructor
CB(const CB &x):p(x.p) {..}
CA::a 10
CA::b 20
CA
H
E
A
P
Shallow Assignment
CB obj3
CB obj3(40,50), obj4;
Obj4 = obj3;
CB obj4
CA *p
&&
Shallow
assignment
CA *p
&&
S
T
A
C
K
compiler synthesized
Assignment function
void operator =(const CB &x)
{
p = x.p;
}
CA::a 40
CA::b 50
CA
LEAKED
MEMORY
CA::a
CA::b
CA
0
0
H
E
A
P
Deep Copy
CB obj2(obj1);
CB obj1
CB obj2
CA *p
&&
CA *p
&&
CA::a 10
CA::b 20
CA
deep
copy
CA::a 10
CA::b 20
CA
S
T
A
C
K
H
E
A
P
Deep Assignment
CB obj3(40,50), obj4;
Obj4 = obj3;
CB obj3
CB obj4
CA *p
&&
CA *p
&&
S
T
A
C
K
CA::a 40
CA::b 50
CA
deep
assignment
CA::a 40
CA::b 50
CA
H
E
A
P
EXPLICIT CONSTRUCTOR
When a method is expecting an object which has a
one-argument constructor but you pass the argument,
compiler will implicitly call that one-argument
constructor and convert that passed argument to the
object:
class Base
{
public:
Base(int a) : member(a)
{
cout << "Base constructor called with " << a << endl;
}
int member;
};
void test(Base obj1)
{ cout << "Base object's member = " << obj1.member; }
EXPLICIT CONSTRUCTOR(contd..)
int main()
{
test(333);
}
The output will be:
Base constructor called with 333
Base object's member = 333
//ERROR
void main()
{
CA *p = new CA;
CA obj;
cout <<" p = "<< p << endl;
cout <<"& obj = " << &obj <<endl;
}
MODULE 6
Example:
TypeName *typeNamePtr;
Creates pointer to a TypeName object
delete typeNamePtr;
Calls destructor for TypeName object and frees memory
Initializing objects
double *thingPtr = new double( 3.14159 );
Initializes object of type double to 3.14159
delete [] arrayPtr;
to delete arrays
Placement new
There are many uses of placement new.
The simplest use is to place an object at a particular
location in memory.
This is done by supplying the place as a pointer
parameter to the newpart of a newexpression:
#include <new> // Must #include this to use "placement new"
class Employee {};
void Fun()
{
char memory[sizeof(Employee)];
void* place = memory;
Employee* f = new(place) Employee();
// The pointers f and place will be equal
...
}
ADVICE: Don't use this "placement new" syntax unless you have to.
Use it only when you really care that an object is placed at a
particular location in memory.
This is about the only time you ever explicitly call a destructor.
MODULE 7
Private Inheritance
Private inheritance gives is-implemented-in-terms-of
relationship:
Inherit just the implementation of the various operations plus data
structures. For example, you may need to operate on data with
more stringent requirements, and so may need to restrict the
original interface.
Further, these traits privately acquired by this derived class is
totally sealed and cannot be inherited further down the inheritance
hierarchy in a multi-level inheritance.
Protected Inheritance
All public features of the base class become protected
features of the derived class (protected features of the
base class continue to be protected in the derived class
- the same for private features)
Useful if you do not want to finalize the derivations, that
is you want to make it possible to have additional derived
classes:
PRIVATE
PROTECTED
PUBLIC
PROTECTED
PUBLIC
PROTECTED PUBLIC
CB
PRIVATE
class CB:private CA
CB
{.};
PRIVATE INHERITANCE
PRIVATE
PROTECTED
PUBLIC
class CB:protected CA
CB
{.};
PROTECTED INHERITANCE
class CB:public CA
{.};
PUBLIC INHERITANCE
class Engine
{
public:
Engine(int numCylinders);
void start();
};
class Car
{
public:
Car() : e_(8) { }
// Initializes this Car with 8 cylinders
void start() { e_.start(); }// Start this Car by starting its Engine
private:
Engine e_;
// Car has-a Engine
};
Hybrid Inheritance
class CA
//BASE CLASS
CA
{ private: int a;
public:
//...
};
CA::a
class CB:public CA
CB::b
CB
CC
CA::a
CC:c
{
private: int b;
public:
//...
CB
CB OBJECT
OBJECT
LAYOUT
LAYOUT
CD
};
class CC:public CA
{
private: int c;
public:
//...
};
CA::a
CB::b
CA::a
CC:c
private: int d;
public:
};
CD::d
//...
CD OBJECT
LAYOUT
CC
CC OBJECT
OBJECT
LAYOUT
LAYOUT
Virtual Inheritance
class CA
//BASE CLASS
{ private: int a;
CA
ptr
ptr
};
CA::a
CA::a
CB::b
public:
//...
CB
CC
CC:c
{
private: int b;
public:
//...
CB
CB OBJECT
OBJECT
LAYOUT
LAYOUT
CD
};
class CC: virtual public CA
{
private: int c;
public:
//...
};
CA::a
ptr
CB::b
ptr
CC:c
CD::d
private: int d;
public:
};
CA::a
//...
CD OBJECT
LAYOUT
CC
CC OBJECT
OBJECT
LAYOUT
LAYOUT
What is OOP?
Object-Oriented Programming is a philosophy where the
source code of a program is split into reusable objects.
What is an object, then?
An object is made of two parts:
- The interface = catalog of the object features
-The implementation = internal machinery
};
private:
// Can only be accessed by Car for its own use.
Aggregation or Composition?
Car
Wheel
Person
Brain
Aggregation is a relationship
in which one object is a part
of another.
Composition is a relationship
in which one object is an
integral part of another
A aggregates B
=
B is part of A, but their
lifetimes may be different
A composes B
=
B is part of A, and their
lifetimes are the same
Ex: cars
and wheels, engine,
c
etc.
A circle is a shape
GeomShape
Circle
class GeomShape {
//
};
class Circle : public GeomShape {
//
};
file.h
Polymorphism
Mechanism that allows a derived class to modify the behavior
of a member declared in a base class
class Employee {
Employee
public :
virtual float income(); // 1000
};
Boss
class Boss : public Employee {
public :
virtual float income(); // 10000
};
Polymorphism (contd..)
A pure virtual function just defines the interface, and leaves
the implementation to derived classes
Employee
class Employee {
public :
Boss
virtual float income() = 0;
// not implemented
};
class Boss : public Employee {
public :
virtual float income(); // implemented
};
Inheritance of
the
implementation
Non virtual
function
Mandatory
Mandatory
Virtual
function
Mandatory
By default,
Possible to
redefine
Pure virtual
function
Mandatory
Re-definition is
mandatory
Virtual
Function
Pure
Virtual
function
Construct
or is
Destructor
is
Isolated
class
No
No
Public
Public
Base class
Yes (must)
Yes / No
Public
Public
Virtual
Pure
Abstract
class
Yes (must)
Yes / No
Protected
Public
Virtual
Derived
(concrete
class)
Yes (must)
No
Public
Public
Virtual
Consequences
Additional guidelines...
Avoid multiple inheritance: use composition
Forbid default parameters in virtual functions
Dont redefine (overload) a non virtual function
Differentiate between layering and inheritance
Advanced Principles of
Class design
Its been blamed on stupidity, lack of discipline, and phases of the moon, but...
A case study
The Copy Routine
First Version
All designs start well
Copy
ReadKeyboard
WritePrinter
void copy(void)
{
int ch;
while( (ch=ReadKeyboard()) != EOF)
WritePrinter(ch);
}
The program is an overnight success!
How could it be more simple, elegant, and maintainable?
Second Version
Oh, no! Nobody said the requirements might change!
ReadKeyboard
WritePrinter
ReadTape
Third Version
How unexpected! Requirements changed again!
void Copy()
{
int c;
while( (c=getchar()) != EOF)
putchar(c);
}
is it?
It is a small program based on abstractions!
FILE is an abstraction
It has methods
Rephrased in OO
Copy
interface
Reader
KeyboardReader
interface
Writer
PrinterWriter
class Reader
{ virtual char read()=0; };
class Writer
{ virtual void write(char c)=0; };
void copy(Reader &itsReader, Writer &itsWriter)
{
int c;
while( (c==itsReader.read()) != EOF )
itsWriter.write(c);
}
ISP:
DIP:
Payroll
Employee
+ CalcPay
+ ReportHours
+ WriteEmployee
Report
Writer
Employee
Payroll
+ CalcPay
Employee
Repository
Open/Closed Principle
Modules should be open for extension, but closed for modification
-Bertrand Meyer
Abstraction is Key
Abstraction is the most importantwordinOOD
Client
Client
Server
Abstract
Server
Concrete
Server
Circle.h
struct Circle
{
enum ShapeType itsType;
double itsRadius;
Point itsCenter;
};
void DrawCircle(struct Circle*)
Square.h
struct Square
{
enum ShapeType itsType;
double itsSide;
Point itsTopLeft;
};
void DrawSquare(struct Square*)
DrawAllShapes.cpp
#include <Shape.h>
#include <Circle.h>
#include <Square.h>
typedef struct Shape* ShapePtr;
void
DrawAllShapes(ShapePtr list[], int n)
{
int i;
for( i=0; i< n, i++ )
{
ShapePtr s = list[i];
switch ( s->itsType )
{
case square:
DrawSquare((struct Square*)s);
break;
case circle:
DrawCircle((struct Circle*)s);
break;
}
}
}
A Closed Implementation
Shape.h
class Shape
{
public:
virtual void Draw() const =0;
};
Square.h
class Square: public Shape
{
public:
virtual void Draw() const;
};
Circle.h
class Circle: public Shape
{
public:
virtual void Draw() const;
};
DrawAllShapes.cpp
#include <Shape.h>
void DrawAllShapes(Shape* list[],int n)
{
for(int i=0; i< n; i++)
list[i]->draw();
}
Strategic Closure
No program is 100% closed.
Closure Against What?
Closure is strategic. You have to choose which changes
youll isolate yourself against.
What if we have to draw all circles first? Now DrawAllShapes
must be edited (or we have to hack something)
Opened Where?
Somewhere, someone has to instantiate the individual
shapes.
Its best if we can keep the dependencies confined
Open/Closed Review
Square/Rectangle
A square is-a rectangle, right? So lets
consider Square as a subtype of Rectangle.
-height : real
-width : real
+SetHeight()
+SetWidth()
Square
void Square::SetWidth(double w)
{
width = w;
height = w;
}
void Square::SetHeight(double h)
{
width = h;
height = h;
}
Substitution denied!
It is reasonable for users of a rectangle to expect that
height and width may change independently.
These expectations are preconditions and
postconditions
- Bertrand Meyer calls it Design by Contract
- Post condition contract for rectangle is
width = new Width
height = old height.
- if ( typeid(r) == typeid(Rectangle) )
- Violates Open/Closed Principle !
- Bertrand Meyer
- Preconditions, postconditions, invariants
LSP Review
Copy
Vs.
ReadKeyboard
Reader
Writer
KeyboardReader
PrinterWriter
WritePrinter
DIP Implications
- Nonvolatile classes
string, vector, etc.
- providing they are stable
Client 1
Client 2
Server
+ C1Function()
+ C2Function()
+ C3Function()
Client 3
A Segregated Example
Client 1
Client 2
Client 3
interface
interface
interface
Client 1
Client 2
Client 3
+ C1Function()
+ C2Function()
Server
+ C1Function()
+ C2Function()
+ C3Function()
+ C3Function()
ATM UI Example
Withdraw
Deposit
Transfer
interface
ATM UI
+ GetWithdrawAmountAndAccount()
+ GetDepositAmountAndAccount()
+ GetTransferAmountAndAccounts()
French ATM UI
English ATM UI
Deposit
interface
ATM Deposit UI
+ GetDepositAmountAndAccount()
Withdraw
Transfer
interface
interface
ATM Transfer UI
ATM Withdraw UI
+ GetWithdrawAmountAndAccount
+ GetTransferAmountAndAccounts()
interface
ATM UI
+ GetWithdrawAmountAndAccount()
+ GetDepositAmountAndAccount()
+ GetTransferAmountAndAccounts()
French ATM UI
English ATM UI
Logger Example
Log Control
Application
Code needing to
log something
interface
LogManager
interface
+ SendLotToFile(name)
EventLog
+ LogToMem(size)
+ Log(s: string*)
+ LogToConsole()
ManagedEventLog
+ Log(s: string*)
+ SendLotToFile(name)
+ LogToMem(size)
+ LogToConsole()
ISP Review
ISP
//function
CA *p = new(nothrow) CB;
p->nonvirtual();
delete p;
VTABLE Layout
void rectangle::draw() { }
circle::~circle() {}
rectangle::~rectangle() {}
& circle::draw()
& circle::~circle()
& rectangle::draw()
& rectangle::~rect()
circle
class
VTABLE
vptr
@@
rectangle class
VTABLE
Circle object
rectangle
object
@@
&&&
&&&
circle *p
S
E
G
M
E
N
T
radius
##
D
A
T
A
circle *p
##
##
##
H
E
A
P
S
T
A
C
K
CC obj1
RTTI
RTTI Table
OBJECT
OBJECT
LOCATOR
LOCATOR
VTABLE
VTABLE
CLASS
CLASS
HIERARCHY
HIERARCHY
-1 &
& RTTI
RTTI OBJECT
OBJECT
COUNT
COUNT
2
(RTTI
(RTTI BASE
BASE CLASS
CLASS ARRAY)
ARRAY)
LOCATOR
LOCATOR
&
& TYPE
TYPE DESCRIPTOR
DESCRIPTOR
&
& RTTI
RTTI BASE
BASE
CLASS
CLASS ARRAY
ARRAY
4 &
& CLASS
CLASS HIERARCHY
HIERARCHY
DESCRIPTOR
DESCRIPTOR
&
& RTTI
RTTI BASE
BASE CLASS
CLASS
DESCPIPTOR.
DESCPIPTOR.
CONST
CONST TYPEINFO
TYPEINFO &
&
2
3
RTTI
RTTI TYPE
TYPE
DESCRIPTOR
DESCRIPTOR
4
5
6
BASE
BASE CLASS
ARRAY
ARRAY
&
& RTTI
RTTI TYPE
TYPE
DESCRIPTOR
DESCRIPTOR
BASE
BASE CLASS
CLASS
DESCRIPTOR
DESCRIPTOR
Example 1
// Getting the run time type information
#include <iostream>
#include <typeinfo>
using namespace std;
// polymorphic base class...
class __rtti Test
{
// This makes Test a polymorphic class type.
virtual void func() {};
};
// derived class...
class Derived : public Test {};
int main(void)
{
// Instantiate Derived type object...
Derived DerivedObj;
// Declare a Derived type pointer
Derived *DerivedPtr;
// Initialize the pointer
DerivedPtr = &DerivedObj;
//continued.
Example 1 (contd..)
// do the run time checking...
if(typeid(*DerivedPtr) == typeid(Derived))
// check the type of *DerivedPtr
cout<<"Ptr *DerivedPtr type name is <<typeid(*DerivedPtr).name();
if(typeid(*DerivedPtr) != typeid(Test))
cout<<"\nPointer DerivedPtr is not a Test class type.\n";
return 0;
}
OUTPUT:
c and f are different type.
int before double: 1
double before int: 0
class A before class B: 1
Example 2
#include <iostream>
#include <typeinfo>
using namespace std;
class Base
{
public:
virtual void funct(){}
};
class Derived:public Base{};
int main()
{
Derived* Test1 = new Derived;
Base* Test2 = Test1;
cout<<"The type name of Test1 is: ";
cout<<typeid(Test1).name()<<endl;
cout<<"The type name of *Test1 is: ";
cout<<typeid(*Test1).name()<<endl;
cout<<"The type name of Test2 is: ";
cout<<typeid(Test2).name()<<endl;
cout<<"The type name of *Test2 is: ";
cout<<typeid(*Test2).name()<<endl;
delete Test1;
return 0;
}
Example 2 (output)
OUTPUT:
The type name of Test1 is: class Derived *
The type name of *Test1 is: class Derived
The type name of Test2 is: class Base *
The type name of *Test2 is: class Derived
Abstract Factory
Intent
Provide an interface for creating families of related or
dependent objects without specifying their concrete
classes.
+createProduct()::AbstractProduct
ConcreteFactory
ConcreteProduct1
ConcreteProduct2
+createProduct()::AbstractProduct
+createProduct()::AbstractProduct
<<creates>>
+createProduct()::AbstractProduct
<<creates>>
Factory Method
Intent
Define an interface for creating an object, but let
subclasses decide which class to instantiate. Factory
Method lets a class defer instantiation to subclasses.
Creator
Product=factoryMethod();
+factoryMethod()::Product
+operation():void
Concrete Product
0..*
ConcreteCreator
<<creates>>
+factoryMethod()::ConcreteProduct
return new
ConcreteProduct();
Singleton
Intent
Ensure a class has only one instance, and provide a
global point of access to it.
Problem
Application needs one, and only one, instance of an
object. Additionally, lazy initialization and global access
are necessary.
Singleton
-instance:Singleton
+Singleton()
+operation():void
+getinstance():instance
Bridge
Intent
Decouple an abstraction from its implementation so
that the two can vary independently.
Bridge (contd..)
Problem
"Hardening of the software arteries" has occurred by using
subclassing of an abstract base class to provide alternative
implementations. This locks in compile-time binding between
Interface and implementation. The abstraction and
implementation cannot be independently extended or
composed.
Abstraction
imp.operatorImpl();
Implementor
imp
<<creates>>
+operationImp():void
+operation():void
RefinedAbstraction
ConcreteImplementorA
ConcreteImplementorB
+operationImp():void
+operationImp():void
Template Method
Intent
Define the skeleton of an algorithm in an operation,
deferring some steps to client subclasses. Template
Method lets subclasses redefine certain steps of an
algorithm without changing the algorithm's structure.
ConcreteClass
+primitiveOperation1():void
+primitiveOperation2():void
primitiveOperation2();
MODULE 8
Class Template
Class templates encourage software reusability by
enabling type-specific versions of generic classes to
be instantiated.
Class templates are called parameterized types,
because they require one or more type parameters to
specify how to customize a "generic class" template to
form a class-template specialization.
The programmer who wishes to produce a variety of
class-template specializations writes only one classtemplate definition.
Class Template
Each time an additional class-template specialization is
needed, the programmer uses a concise, simple
notation, and the compiler writes the source code for
the specialization the programmer requires.
//A complete generic class supporting two unique types
template<typename T1, typename T2> class CA
{.....};
Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Example(contd..)
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
Example(contd..)
51 template< typename T >
52 bool Stack< T >::push( const T &pushValue )
53 {
54
if ( !isFull() )
55
{
56
stackPtr[ ++top ] = pushValue; // place item on Stack
57
return true; // push successful
58
} // end if
59
60
return false; // push unsuccessful
61 } // end function template push
62
63 // pop element off Stack;
64 // if successful, return true; otherwise, return false
65 template< typename T >
66 bool Stack< T >::pop( T &popValue )
67 {
68
if ( !isEmpty() )
69
{
70
popValue = stackPtr[ top-- ]; // remove item from Stack
71
return true; // pop successful
72
} // end if
73
74
return false; // pop unsuccessful
75 } // end function template pop
76 #endif
Code Blow
Whenever we are designing generic classes we got to
look into an very important issue called code-blow.
What is code-blow?
Code-blow is nothing but redundant or unwanted code
instantiated by the compiler without the knowledge of the
generic class consumer.
When does it happen?
If a generic class consists of any member function(s)
dealing only with type-specific data and generic, then
such a situation is possible.
Consider the example in the following slide.
Given the code above, we would notice that the compiler would
have instantiated or generated 2 PrintInt() functions where both
functions deal only with int type data no matter the object is
specialized for int or float type.
Introduction
Structure of STL
Containers
Sequence Containers
Organizes a finite set of same type objects into a strictly
linear arrangement
There are 3 basic types - vector, list and deque
The containers queue and stack are implemented using
deque
The following are the header files used:
Header
vector
list
deque
queue
stack
Contents
An array of T
A doubly linked list of T
A double ended queue of T
A queue of T
A stack of T
Associative Containers
Facilitates fast retrieval of data based on keys
There are four types of associative containers - set,
multiset, map, multimap
Parameterized on key and an ordering relation Compare
The keys in set and map are unique keys
The keys in multiset and multimap are equal keys
The following header files are used:
Header
map
set
bitset
Contents
An associative array of T
A set of T
A set of Boolean values
Size: 1
Capacity: 10
There's room for 9 elements before reallocation
Size: 20
Capacity: 20
//insert an element
//insert an element
#include<iostream>
#include<vector>
using namespace std;
int main(){
//Create a vector of Short integers.
vector <short> vs;
vs.push_back(1);
vs.push_back(2);
vs.push_back(3);
vs.push_back(4);
//insert
//insert
//insert
//insert
an
an
an
an
element
element
element
element
<<
<<
<<
<<
This example illustrates the use of push(), pop(), Front and Back
operations on a queue object.
#include<iostream>
#include<queue>
using namespace std;
int main(){
queue <int> iq; // Create an integer queue object
iq.push(29);
iq.push(239);
iq.push(344);
iq.push(541);
cout << "Size of the queue is: " << iq.size() << endl;
while (!iq.empty()){
cout << "The top most element is: " << iq.front() << endl;
cout << "The bottom most element is: " << iq.back() << endl <<
endl;
iq.pop();
}
return 0;
}
Algorithms
STL contains a rich collection of algorithms that can be
applied to a variety of containers.
There are approximately 70 standard algorithms
Operate on elements of containers indirectly through
iterators
There are three main types of algorithms.
Non-mutating sequence operations
Mutating sequence operations
Sorting Algorithms
Sorting operations
Algorithms for sorting and merging sequences
Algorithms for set operations for sorted sequences
Includes sort(), partial_sort(), binary_search(), for
example
Example
sort( ) - takes two arguments of type const iterator that
point to the beginning and the end of the sequence
respectively.
MODULE 9
Exception Handling
Ignore exceptions!
Abort program - what if resources were allocated to a
program and it aborted? ("Resource Leak")
Set and test error indicators - need to check them at all
points in the program
Handler class
try Block
throw Expression
Control
constructor
Control
Catch function
Control
FUNCTION
Invoking of Handler
The Type of the Object Argument of the throw
Expression Determines the Appropriate catch
Invocation
A throw Expression Without an Argument Re-throws
the Exception Being Handled Again. Such a throw
Expression MAY APPEAR ONLY IN A HANDLER or in
a Function Directly Called From the Handler
The catch (...) Handler, if Present, CAN Handle ALL
Exception Classes
Invoking of Handler
If NO Appropriate Handler is Present, the
unexpected() Function is Invoked. It Passes the
Control to terminate() Function and can Cause
Termination
The throw Expression is First Passed to the
Appropriate Constructor for the Class -- A Default
Constructor MAY be Created, if Needed -- No
Constructor is Used for Non-Classes. The Processing
is then Passed to the Handler
catch Handlers
The catch Handler MUST IMMEDIATELY FOLLOW
the Appropriate try Block or Other catch Handlers
The Placement Order is Significant. Control is
Passed to the FIRST HANDLER THAT CAN
HANDLE THE CONDITION
The catch(...) Handler, if Present, SHOULD BE THE
LAST HANDLER
<< endl;
endl;
zero_check(i);
cout << "Reciprocal: " << 1.0/i << endl;
}
}
//Handler
catch(zero)
{cout << "DIVIDE BY ZERO -- ERROR!!\n"; exit(-1);}
}
// terminate normally
Throwing an Exception
if ( denominator == 0 )
throw DivideByZeroException();
Throws a dividebyzeroexception object
Catching an Exception
Exception handlers are in catch blocks
Format: catch( exceptionType parameterName)
{
exception handling code
}
Rethrowing an Exception
Rethrowing exceptions
Used when an exception handler cannot process an
exception
Rethrow exception with the statement: throw;
No arguments
If no exception thrown in first place, calls
terminate
throw;
int main()
{
try {
throwException();
cout << "This should not print\n";
}
catch ( exception e )
{
cout << "Exception handled in main\n";
}
cout << "Program control continues after catch in main" << endl;
return 0;
}
OUTPUT:
Function throwException
Exception handled in function throwException
Exception handled in main
Program control continues after catch in main
Exception specifications
Example:
int g( double h ) throw ( a, b, c )
{
// function body
}
Function can throw listed exceptions or derived types
If other type thrown, function unexpected called
throw() (i.e., no throw list) states that function will not throw any
exceptions
In reality, function can still throw exceptions, but calls unexpected
(more later)
Function unexpected
Calls the function specified with set_unexpected
Default: terminate
Function terminate
Calls function specified with set_terminate
Default: abort
Usages
Example-4
// domain_error and typeid()
#include <iostream>
using namespace std;
int main()
{
try
{
throw domain_error("Some error with your domain!");
}
catch (exception &err)
{
cerr<<"Caught: "<<err.what()<<endl;
cerr<<"Type: "<<typeid(err).name()<<endl;
};
}
Output:
Caught: Some error with your domain!
Type: class std::domain_error
Example-5
// bad_typeid
#include <typeinfo>
#include <iostream>
using namespace std;
class Test
{
public:
// object for a class needs vtable for the rtti
Test();
virtual ~Test();
};
int main()
{
Test *ptrvar = NULL;
try {
// the error condition
cout<<typeid(*ptrvar).name()<<endl;
}
catch (bad_typeid)
{
cout<<"The object is NULL"<<endl;
}
}
Output:
The object is NULL
Example-6
// set_unexpected()
#include <exception>
#include <iostream>
using namespace std;
void myfunction()
{
cout<<"Testing myfunction()."<<endl;
// terminate() handler
terminate();
}
int main( )
{
unexpected_handler oldHandler = set_unexpected(myfunction);
// unexpected() function call
unexpected();
}
Output:
The Debug Error message box should be expected.
Anonymous namespace
References
C++ Primer by Lippman.
Inside Objects by Lippman
C++ By Bjarne Stroustrup
C++ Bible by AL Stevens
Complete Reference by Herbert Schildt.
Advanced C++ James coplin
Effective C++ Scott meyers
More Effective C++ Scott meyers
Effective STL Scott meyers
Design Patterns (GOF)