0% found this document useful (0 votes)
96 views

SE - Lecture 03-30 (OOP in C++)

The document provides an overview of object-oriented programming in C++. It discusses procedural enhancements in C++ over C like const-ness, references, inline functions, default function parameters, and function overloading. It also covers topics like pointers vs references, macros, returning references, and overload resolution with const, references, and expressions. The document is intended to teach programming concepts in C++ through lectures and examples.

Uploaded by

Avinash Gupta
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)
96 views

SE - Lecture 03-30 (OOP in C++)

The document provides an overview of object-oriented programming in C++. It discusses procedural enhancements in C++ over C like const-ness, references, inline functions, default function parameters, and function overloading. It also covers topics like pointers vs references, macros, returning references, and overload resolution with const, references, and expressions. The document is intended to teach programming concepts in C++ through lectures and examples.

Uploaded by

Avinash Gupta
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/ 217

Object-Oriented

Programming in C++
CS20006:SoftwareEngineering
Lecture 03Prof.Partha Pratim Das

Jan-Feb 2016

Object-Oriented Modeling & Programming

PROGRAMMING IN C++
Jan-Feb 2016

Topics

Procedural Enhancements in C++ over C


Classes
Overloading
Inheritance
Type Casting
Exceptions
Templates
Jan-Feb 2016

Object Oriented Programming in C++

PROCEDURAL
ENHANCEMENTS IN C++
Jan-Feb 2016

TOPICS

Const-ness
Reference Data Type
Inline Functions
Default Function Parameters
Function Overloading & Resolution
Dynamic Memory Allocation

Jan-Feb 2016

const Quantifier
const qualifier transforms an object into a
constant.
Example: const int capacity = 512;
Any attempt to write a const object is an error
Const object must be initialized.

Pointer to a non-constant object cannot point to


a const object;
const double d = 5.6;
double *p = &d; //error

Pointer to a constant object vs. constant pointer


to an object.
const double * pConstantObject;
double * const *pConstantPointer;
Jan-Feb 2016

References
A reference is an additional name / alias
/ synonym for an existing variable
Declaration of a Reference
<type> & <name> = <existing variable>;

Examples of Declaration
int j = 5;
int& i = j;

Jan-Feb 2016

References
Wrong declarations
int& i;
// must be initialized
int& j = 5;
// may be declared as const reference
int& i = j+k; // may be declared as a const reference

Often used as function parameters :


called function can change actual argument
faster than call-by-value for large objects

Jan-Feb 2016

References Do not ..
Cannot have an array of references
No operator other than initialization are valid on a
reference.
Cannot change the referent of the reference (Reference
can not be assigned)
Cannot take the address of the reference
Cannot compare two references
Cannot do arithmetic on references
Cannot point to a reference

All operations on a reference actually work on the


referent.
Jan-Feb 2016

Call-by-Reference
Calling by Reference
Parameters can be passed by
reference w/o copy
A reference parameter is an in-out
parameter (read-write)
Recall: A call-by-value parameter is
an input parameter
A const reference parameter is an
input only parameter (read-only)
Jan-Feb 2016

10

Call-by-Reference
Thumb Rules
Pass parameters of built-in types by
value
Recall: Array parameters are passed
by reference in C
Pass parameters of user-defined
types by reference
Make a reference parameter const if it
is not used for output
Jan-Feb 2016

11

Returning a Reference
Returning a reference
return value is not copied back
may be faster than returning a value
calling function can change returned
object
cannot be used with local variables

Jan-Feb 2016

12

Example

Jan-Feb 2016

13

Returning a Reference
#include <iostream>
using namespace std;
int& max(int& i, int& j) {
if (i > j)
return i;
else
return j;
}
int main(int, char *[]) {
int x = 42, y = 7500, z;
z = max(x, y) ; // z is now 7500
max(x, y) = 1 ; // y is now 1
cout << "x = " << x;
cout << " y = " << y;
cout << " z = " << z << "\n";
return 0;
}
Jan-Feb 2016

14

Pointers vs. References


Pointers can point to NULL whereas References
cannot. There is nothing defined as NULL
Reference.
Pointers can point to different variables at
different times whereas for a reference, its
referent is fixed.
References make code faster since, unlike
pointers, checks for NULL are not required.
Reference refers to an address but does not
store that address. Pointer does.

Jan-Feb 2016

15

Macros
Macros are expanded at the places of their calls.
Advantages:
Speed-wise efficient

Disadvantages:
Parameter passing mechanism is not robust and
frequently leads to errors.
Type checking during parameter passing is not done

Code size tend to increase

Typical Use:
Small code re-use

Jan-Feb 2016

16

Inline Functions
Inline functions act like functions

They
Type
They
They

can be class members


checking is performed
can be overloaded
obey normal parameter passing rules

But they are implemented like macros

Code is substituted inline, not called


Use is faster than calling a function
Use may take more space
They are defined in .h files, not in .c/.cxx
files

Jan-Feb 2016

17

Inline Notes
inline specification is only a
recommendation.
A recursive or a large function may not
be inline.
Unlike a non-inline function, an inline
function must be defined in every text
file where it is called.
Inline functions must not have two
different definitions.
May cause unexpected behavior if compiler
does not chose to make the function inline.
Jan-Feb 2016

18

Default Function Arguments


Default arguments are appropriate argument
value of a parameter for a majority of cases.
Default arguments can be supplied to one or
more parameters.
Default arguments may be expressions also.
All parameters to the right of a parameter with
default argument must have default arguments.
Default arguments cannot be re-defined.
Default parameters should be supplied only in a
header file and not in the definition of a function.
Jan-Feb 2016

19

Default Arguments: Example


Following are some examples of
functions with default arguments.
Void ff (int, float = 0.0, char *);
Void ff2(int, float = 0, char *=NULL);
Void ff2(int float = 1, char *= NULL);

// Error
// OK
// Error Redefinition

Assume that ff.h contains the following declaration


ff(int, float, char = a);

Wrong example:
#include ff.h
ff(int i, float f = 0.0, char ch = a); //Error

However, the following are correct.


#include <ff.h>
ff(int i, float f = 0.0, char ch); //OK
ff(int i = 0, float f, char ch); //OK
Jan-Feb 2016

20

Function Overloading
The same function name may be used in several definitions.
Functions with the same name must have different number of
formal parameters and/or different types of formal
parameters.
Function selection based on number and types of the actual
parameters at the places of invocation.
Function selection (Overload Resolution) is performed by the
compiler
Two functions having the same signature but different return
types will result in a compilation error due to attempt to redeclare.
Overloading allows static polymorphism

Jan-Feb 2016

21

Overload Resolution
Steps to resolve overloaded functions
with one parameter
Identify the set of candidate functions and
the set of viable functions.
Select the best viable function through
(Order is important)

Jan-Feb 2016

Exact Match
Promotion
Standard type conversion
User defined type conversion
22

Overload Resolution
Steps to resolve overloaded functions
with one parameter
Example:
1. void f();
2. void f(int);
3. void f(double, double = 3.4);
4. void f(char, char *);
f(5.6)
Candidate function: 2 & 3
Best function: 3
Jan-Feb 2016

23

Exact Match
lvalue-to-rvalue conversion
Most common

Array-to-pointer conversion
Definitions: int ar[10]; void f(int *a);
Call: f(ar)

Function-to-pointer conversion
Definitions: typedef int (*fp) (int);
void f(int x, fp); int g(int);
Call: f(5, g)

Qualification conversion
Converting pointer (only) to const pointer.
Jan-Feb 2016

24

Promotion & Conversion


Examples of Promotion
char to int; float to double
enum to int/long/unsigned int/
bool to int

Examples of Standard Conversion


integral conversion
floating point conversion
floating point Integral conversion
The above 3 may be dangerous!
pointer conversion
bool conversion

Jan-Feb 2016

25

Examples of Resolution
int f(int, int)
{ cout << "int f(int, int)" << endl; return 0; }
void f(int, void *)
{ cout << "void f(int, void *)" << endl; return; }
void f(int, char *)
{ cout << "void f(int, char *)" << endl; return; }
double f(int)
{ cout << "double f(int)" << endl; return 0.0; }
int f(double)
{ cout << "int f(double)" << endl; return 0; }
void f()
{ cout << "void f()" << endl; return; }
void f(int[])
{ cout << "void f(int[])" << endl; return; }
typedef void (*fp) (int);
void f(int x, fp)
{ cout << "void f(int x, fp)" << endl; return; }
void g(int) {} void h(int) {}
Jan-Feb 2016

26

Examples of Resolution
int f(int, int);
void f(int, void *);
void f(int, char *);
double f(int);
int f(double);
void f();
void f(int[]);
typedef void (*fp) (int);
void f(int x, fp);
void g(int) {}
void h(int) {}

Jan-Feb 2016

int main() {
int a = 2, b = 3, *q = &a;
char *p = 0; double d = 5.2;
f(a, b);
// int f(int, int)
f(a, p);
// void f(int, char *)
f(a);
// double f(int)
f(d);
// int f(double)
f();
// void f()

27

Examples of Resolution
int f(int, int);
void f(int, void *);
void f(int, char *);
double f(int);
int f(double);
void f();
void f(int[]);
typedef void (*fp) (int);
void f(int x, fp);
void g(int) {}
void h(int) {}

Jan-Feb 2016

int main() {
int a = 2, b = 3, *q = &a;
char *p = 0; double d = 5.2;
...
f(4, 5);
// int f(int, int)
f(8, q);
// void f(int, void *)
f(7);
// double f(int)
f(7.0);
// int f(double)
f(4.6, 5);
// int f(int, int)
28

Examples of Resolution
int f(int, int);
void f(int, void *);
void f(int, char *);
double f(int);
int f(double);
void f();
void f(int[]);
typedef void (*fp) (int);
void f(int x, fp);
void g(int) {}
void h(int) {}

Jan-Feb 2016

int main() {
int a = 2, b = 3, *q = &a;
char *p = 0; double d = 5.2;
...
f(q);
// void f(int[])
f(5, &g);
// void f(int x, fp)
f(5, h);
// void f(int x, fp)
return 0;
}

29

Overload Resolution with


const, reference & expression
void f(T1); void f(T2);
T1, T2

int

const
int

int&

const int&

int

redef
error

int a, b;
f(a); //
f(a+b); //
f(7); //

int a, b;
f(a); //
f(a+b); //
f(7); //

const int

int a, b;
f(a); //
f(a+b); //
f(7); //

int a, b;
f(a); //
f(a+b); //
f(7); //

int&

const int&

Jan-Feb 2016

int a, b;
f(a); //
f(a+b); //
f(7); //
X
30

Overload Resolution with


const, reference & expression
void f(T1); void f(T2);
T1, T2

int

const
int

int&

const int&

int

redef
error

int a, b;
f(a); // ambiguous
f(a+b); // ok int
f(7); // ok int

int a, b;
f(a); // ambiguous
f(a+b); // ambiguous
f(7); // ambiguous

const int

int a, b;
f(a); // ambiguous
f(a+b); // ok const int
f(7); // ok const int

int a, b;
f(a); // ambiguous
f(a+b); // ambiguous
f(7); // ambiguous

int&

int a, b;
f(a); // ok int&
f(a+b); // ok const int &
f(7); // ok const int &

const int&

Jan-Feb 2016

31

Overload Resolution with


const int & double

void f(T1);
void f(T2);

Jan-Feb 2016

T1, T2

double

int

int a;
f(a); //
f(7); //

const int

int a;
f(a); //
f(7); //

int&

int a;
f(a); //
f(7); //

const int&

int a;
f(a); //
f(7); //
32

Overload Resolution with


const int & double

void f(T1);
void f(T2);

Jan-Feb 2016

T1, T2

double

int

int a;
f(a); // ok int
f(7); // ok int

const int

int a;
f(a); // ok const int
f(7); // ok const int

int&

int a;
f(a); // ok int&
f(7); // ok double

const int&

int a;
f(a); // ok const int&
f(7); // ok const int&
33

Operator & Operator Function


What is the difference between an
operator and a function?
Notation!
Operator:
Infix: a + b; a ? b : c;
Prefix: ++a;
Postfix: a++;

Function:
Prefix: max(a, b);
qsort(int[], int, int, void (*)(void*, void*));
Jan-Feb 2016

34

Operator & Operator Function


Every operator has a function that
defines its behaviour implicit for
predefined operators of built-in types
For example, for int a = 2, b = 3, c;
c = a + b;

is equivalent to:
int operator+(int x, int y);
c = operator+(a, b);
Jan-Feb 2016

35

Operator & Operator Function


C++ allows you to define your
operators function & overload it
Operators for built-in types cannot be
redefined

Jan-Feb 2016

36

Overload Operator+
#include <iostream>
using namespace std;
enum E {C0 = 0, C1 = 1, C2 = 2};
int main() {
E a = C1, b = C2;
int c = -1;

Output:
3

c = a + b;
cout << c << endl;
return 0;
}

Jan-Feb 2016

37

Overload Operator+
#include <iostream>
using namespace std;

int main() {
E a = C1, b = C2;
int c = -1;

enum E {C0 = 0, C1 = 1, C2 = 2};


c = a + b;
cout << c << endl;

E operator+(const E& a, const E& b) {


unsigned int uia = a, uib = b;
unsigned int t = (uia + uib) % 3;

return 0;
}

return (E) t;
}

Output:
0

Jan-Feb 2016

38

Examples of Resolution
(Conflict)
1. Promotion
enum e1 { a1, b1, c1 };
enum e2 { a2, b2, c2 =
0x80000000000 };
char *f(int);
char *f(unsigned int);
int main() {
f(a1); // Which f?
f(a2); // Which f?
}

Jan-Feb 2016

2. Standard Conversion
void print(int);
void print(char *);
void set (int *);
void set (const char *);
int main() {
print(0); // Which print?
set(0);
// Which set?
}

39

new/delete operators
In C++, the new and delete operators provide built-in
language support for dynamic memory allocation and deallocation.
int *pI = new int;
int *pI = new int(102); //new initializes!!
int *pArr = new int[4*num];
Arrays generally cannot be initialized.
const int *pI = new const int(100);
Array of constant cannot be created.
delete pI;
delete [] pArr;

new is polymorphic
new does more than malloc!
Jan-Feb 2016

40

new/delete & malloc/free


All C++ implementations also permit use of
malloc and free routines.
Do not free the space created by new.
Do not delete the space created by malloc

Results of the above two operations is memory


corruption.

Matching operators
malloc-free
new-delete
new[] delete[]

It is a good idea to use only new and delete in


a C++ program.
Jan-Feb 2016

41

Object Oriented Programming in C++

CLASS
Jan-Feb 2016

42

TOPICS

Class Members
Constructor & Destructor
Friends
Static Members
Struct & Union

Jan-Feb 2016

43

Class
C++ Class is an implementation of type
In C++, class is the only way to implement user
defined data types
A C++ class contains data members/attributes to
specify the state and operations/methods to specify
the behavior
Thus, classes in C++ are responsible to offer
needed data abstraction/encapsulation of Object
Oriented Programming
C++ Classes also provide means (through access
specifier) to enforce data hiding that separates
implementation from interface
Jan-Feb 2016

44

Class
A Class is defined by class keyword
Each member in a class has an access specifier
private accessible inside the definition of the
class
public accessible everywhere
Objects/instances of classes are to be created
statically or dynamically
Members can be accesses by . operator on the
object
The implicit this pointer holds the address of any
object.
this pointer is implicitly passed to methods.
Jan-Feb 2016

45

A Simple Class
class Employee {
public:
void setName (const char *x)
{ name = strdup(x); }
void setSalary (float y)
{ salary = y; }
char *getName ( )
{ return name; }
float getSalary ( )
{ return salary; }
private:
char *name;
float salary;
};
Jan-Feb 2016

int main ()
{
Employee e1; Employee *e2;
e2 = new Employee;
e1.setName("Amit");
e2->name = strdup("Ashis");
// Error
e1.setSalary(29100);
e2->setSalary(29100);
}
Re-look at
void setName (const char *x)
{ name = strdup(x); }
Whose name?
void setName (const char *x)
{ this->name = strdup(x); }
46

More on this
Type of this
X * const

Necessity of this to the programmer


Distinguishing data member from nonmember variable
Explicit Use
class DoublyLinkedNode {
DoublyLinkedNode *prev, *next;
int data;
public:
void append(DoublyLinkedNode *x);
}
Jan-Feb 2016

DoublyLinkedNode::
append(DoublyLinkedNode *x) {
next = x;
x->prev = this;
}

47

Constructor Functions
Constructor functions:
are member functions with the same name
as the class
are automatically called when an object is
created, just after memory allocation
In case of auto/static variables, objects are created in
the stack/static Store when their definition is
encountered
Objects can be created in the Free store with a pointer
storing the address.

allow the class to initialise the state of an


object
Jan-Feb 2016

48

Constructor Functions
Constructor functions:
Constructors also allocate additional
memory space from the Free store (if)
required for the object
Must not have any return type even void
Default constructors are those constructors
which either do not have an argument or
have default arguments for all parameters
If users do not define any constructor then
the compiler provides a default constructor
Jan-Feb 2016

49

Additional Constructor Functions


Constructor function can be overloaded
Constructor functions can be directly
called to create anonymous objects
Calling a constructor from a constructor
does not have the desired effect
If there is at least one definition of
constructor but no default constructor
then the following statements are
incorrect
X a;
X *pX = new X();

Jan-Feb 2016

50

Destructor Functions
Destructor function:
is a member function named ~ <class-name> (e.g. ~
String ( ) )

is automatically called when an object is destroyed,


just before memory is freed

For auto variables when the variable goes out of scope


For objects created in the Free store, destructor is called after
delete or delete[] is explicitly invoked by the programmer.

must not have any argument or return value

If destructor is not called then there could be


memory leaks for objects which calls new in
the constructor
Jan-Feb 2016

51

Copy Constructor
Copy constructor is a special
constructor which is used to initialize an
object with another object of the same
type.
Copy constructor of class X takes an
argument of type X&.
If the type of argument is X in stead of X&,
an infinite loop results.

Jan-Feb 2016

52

Copy Constructor
Situations where copy constructor is
used:
Actual parameter passing in call-by-value
Return Value passing
Initializing an object with an object of the
same type as shown in the following
example.

The compiler provides a default


implementation of the copy constructor.
Jan-Feb 2016

53

A Sample Class : String


class String {
public:
String();
String(const String&); // Copy Constructor
String(const char *);
~String();
int length();
int read();
void print();
private:
char *data;
int len;
}

Jan-Feb 2016

54

Class String::Constructor &


Destructor
String::String() {
data = NULL;

int main()
{
String s1; //default constructor

len = 0;
}

String s11(); //Error


String s1(test);

String::String(const char *s) {

char str[6];

data = new char[strlen(s)+1];

strcpy(str, Hello);

len = strlen(s);

String s2(str);

strcpy(data, s);

String s3(s2); //Copy Constructor

String s4 = new String(one);


String s5 = new String();

void ~String() {

delete s4;

if (data != NULL)

delete s5;

delete [] data;
}

}
Jan-Feb 2016

55

Arrays
Using Default constructor while
creating an array of objects

String arrayOfString[100]; // 100 objects created using the


default constructor

Using specialized constructor while


creating an array of objects.

String arrayOfString[2] = { String(abc), String(def) };

Using different constructor for creating


array objects dynamically.

String *pArrayOfString[2] =
{ new String(abc), new String(def) };

Jan-Feb 2016

56

Copy Assignment Operator


class String {
public:
String();
String(const String&);
String(const char *);
~String();
int length();
int read();
void print();
Bug:
private:
char *data;

int len;
}

String a(123), b(456);


b = a; // b.operator=(a);
String String::operator=(const String& rhs)
{
len = rhs.len;
data = new char[len + 1];
strcpy(data, rhs.data);
return *this ;
}

The following assignment cannot be


made
String x(abc), y(def), z(ghi);
x = y = z;
(x.operator=((y).operator=(z)));

Solution
Change the return type to String &
Jan-Feb 2016

57

Copy Assignment Operator


String a(123), b(456);
b = a; // b.operator=(a);
String& String::operator=(const String& rhs) {
len = rhs.len;
data = new char[len + 1];
strcpy(data, rhs.data);
Bug:
return *this ;
Memory
}

String a(123), b(456);


b = 123; // b.operator=(123);

Leak as
previous data of this is
not deleted.

String& String::operator=(const char *rhs) {


len = strlen(rhs);
data = new char[len + 1];
strcpy(data, rhs);
return *this ;
}
Jan-Feb 2016

58

Copy Assignment Operator


String& String::operator=(const String& rhs)
{
len = rhs.len;
delete [] data;
data = new char[rhs.len + 1];
strcpy(data, rhs.data);
return *this ;
}

Bug:
Self Assignment will cause problem
Solution:
Check the following condition and return if
false.
if (this != rhs) .
Jan-Feb 2016

59

Copy Assignment Operator


String& String::operator=(const String& rhs)
{
if (this != rhs) {
len = rhs.len;
delete [] data;
data = new char[rhs.len + 1];
strcpy(data, rhs.data);
}
return *this ;
}

Jan-Feb 2016

60

More On = Operator
Overloading
There is a system defined implementation of
assignment operator. In absence of user defined
assignment operator function, systems function is
used.
System defined function makes a shallow copy.
Some times shallow copying may be dangerous

If the constructor uses new, assignment operator


may have to be overloaded.
If there is a need to define a copy constructor then
there must be a need to overload assignment
operator and vice-versa.
Jan-Feb 2016

61

Object Layout
Simplistically, an object
of a class must have
enough space to store all
members of that class.
No space is required per
object for storing function
pointers for the methods
declared in the class.

Methods on objects are


translated by the
compiler to C-like
function calls by passing
this pointer.

Jan-Feb 2016

A String Object
data
len

H e l l o \n

62

Members as Objects
Sometimes a class may have a data attribute
which is an object of a class.
Employee class may have a member name whose
type is String.

When an Employee object is initialized then


name must also be initialized.

Jan-Feb 2016

63

Members as Objects
Initialization of member objects can be arranged
through the use of initializer lists
Initializer lists appear as a comma separated list

following a colon, after a constructors parameters


and before the constructor definition
where each list item is a named member object followed by its
initializer value in parenthesis

Initializer lists are required for a member object that


must be passed initial arguments for construction
Initializer lists are required for const members and
reference members

Jan-Feb 2016

64

Class Member: Notes


It is always a good idea to define data members as
private.
Composition through objects are preferred over
Composition through pointers
Saves time and life cycle management
Not possible in a number of situations

Contained object is shared by many containers.


Contained object may not always be present.

Methods should not return non-const reference or


pointer to less accessible data
Defeats basic data hiding philosophy.
May also lead to stunning consequences.
Jan-Feb 2016

65

Const Member Functions

Constant Member Functions


are not allowed to change
the state of the object on
which they are invoked.
Const Functions are declared
with keyword const following
member function parameter
list.
const must also be present
at the definition.
Type of this pointer passed
to a const function is
const X* const this

Jan-Feb 2016

class X {
private:
int ipriv;
public:
int ipub;
int f() const;
};

int X::f() const


{
int temp;
temp = ipriv + ipub; //accessing members OK
ipriv += temp; // cannot modify any member
ipub -= temp; // cannot modify any member
}

66

Friend Functions
Friend functions
are declared in one or more classes
have access to the private members of
those classes
are distinguished from members with
the keyword friend
are not called with an invoking object
of those classes
Jan-Feb 2016

67

Friend Functions: Example


class String {
public :
String();
String(const char *);
String(int len);
friend String concat(String*, String*);
friend String concat(String*, char*);
friend String concat(char*, String*);
private :
char *data;
int len;
} ;
String::String(int len)
{
this->len = len;
data = new char[len+1];
data[len] = \0;
}

Jan-Feb 2016

String concat(String *left, String *right)


{
String both[left->len + right->len + 1];
strcpy(both.data, left->data);
strcat(both.data, right-> data) ;
return both;
}
String concat(char *left, String *right)
{
String both[strlen(left) + right->len + 1];
strcpy(both.data, left);
strcat(both.data, right->data);
return both;
}

68

Friends of More Than One class


class Matrix; // Forward declaration to make
// declaration of crossprod legal
class Vector {
public :
Vector(int n) ;
friend Vector prod(Matrix *pM, Vector *pV);
private :
int elements[10] ;
int n;
};
class Matrix {
public :
Matrix(int m, int n) ;
friend Vector prod(Matrix *pM, Vector *pV);
private :
int elements[10][10];
int m, n;
};

Jan-Feb 2016

Vector prod(Matrix *pM, Vector *pV)


{
int V(pM->m);
for (i = 0; i < pM->m; i++)
for (j = 0; j < pM->n; j++)
{
v[i] += pM->elements[i][j]*
pV->elements[i];
}
}

69

Friend Members & Class

Member of a different class


may be a friend function.
A class may be declared as a
friend implying all member
functions of that class are
friends.
Friend-ship is neither
commutative nor transitive.
Friends tend to break data
hiding.
It is best to avoid friend in
an ideal OO Design.

Jan-Feb 2016

class Matrix;
class Vector {
public:
void Vector(int n);
Vector prod(Matrix *pM);
int elements[10];
int n;
} ;
class Matrix {
public:
void Matrix(int m, int n);
friend Vector Vector::prod(Matrix *pM);
private:
int elements[10][10];
int m, n;
} ;

70

Static Data
A static data member is
shared by all the objects
of a class.
Static data member may
be public or private.
Static data member must
be initialized in a source
file.
It can be accessed

with the class-name


followed by the scope
resolution operator ::
as a member of any
object of the class

Jan-Feb 2016

X.h
--class X {
public:
static int count; // This is a
declaration
X() { count++; }
}
X.cxx
----#include X.h
int X::count = 0; //Definition & Initialization
int main()
{
X a, b, c;
printf(%d %d %d %d\n, X::count, a.count,
b.count, c.count);
}

The output will be 3 3 3 3


71

Static Data: A List


class ListNode {
public:
static ListNode *first;
private:
ListNode *next;
int data;
public:
ListNode(int x);
print();
}
ListNode *ListNode::first = NULL;
ListNode::ListNode(int x) {
data = x;
next = NULL;
if (first == NULL)
first = this;
else
{
next = first;
first = this;
}
}
Jan-Feb 2016

void ListNode::print() {
ListNode *x;
x = ListNode::first;
while (x != NULL)
{
printf(%d , x->data);
x = x->next;
}
printf(\n);
}
int main() {
ListNode x(5);
ListNode x(7);
ListNode x(8);
x.print();
}

The output will be 8 7 5


72

Static Member Functions


Static member functions
May be invoked
with the class-name::
class_name::static_function (args)

as part of any objects interface


any_object.static_function (args);

this pointer is not passed to a static


function
must not refer to non-static members of
its invoking object
Philosophy of static members.
Jan-Feb 2016

73

Static Members in Inline


Functions
Not Safe
X.hxx
Class X
{
public:
static void f();
static String g();
private:
static String s;
}
inline String X::g()
{
// do some operation on s
return s;
}

Jan-Feb 2016

X.cxx
#include X.hxx
void X::f()
{
X::g();
}

The above code will not fail;


The code in the following
may fail however.
X1.cxx
#include X.hxx
int main()
{
X::g();
}

Data members are


guaranteed to be
initialized before any noninline function is called.
74

Object Oriented Programming in C++

OPERATOR OVERLOADING
Jan-Feb 2016

75

Overloading Operators
Semantics of an operator is
represented by a function named
operator op, where op is an operator
symbol (+,*, - , [ ], etc. )
These functions can either be
implemented as global friend functions
and/or methods.

Jan-Feb 2016

76

Overloading Operators
Example
Let + denote concatenation for Strings.
s1 + s2 denote concatenation of strings s1
and s2.
An expression of the form s1+s2 is
converted to s1.operator+(s2) if there is a
function named operator+ defined in the
class String.
s1+s2 is also equivalent to operator+(s1,
s2) if a global function named operator+ is
properly defined; typically such global
functions are friends to the class String.
Jan-Feb 2016

77

Example of overloading
operator +
/ * string .h * /
const int max_string_length = 128 ;
class String {
public :
String operator + (char *text) ;
String operator + (String &s1) ;
String (char *data);
String () { data = NULL; len = 0; }
private :
char *data;
int len;
};

Jan-Feb 2016

String operator+(char * text)


{
char *save = new char[len+1];
strcpy(save, data);
data = new char[len +strlen(text) +
1];
strcpy(data, save);
stcat(data, text);
delete[]save;
return (*this);
}

78

Reference & Overloading


Suppose that we have a
class Integer which has a
private data member as
int. The following
function is declared as a
friend of Integer.
Integer & operator*(Integer &lhs,
Integer &rhs) {
Integer result = lhs.data *
rhd.data;
return result;
}

Problem: Returning
reference to a local
object. The code fails.
Jan-Feb 2016

Integer & operator*(Integer &lhs,


Integer &rhs)
{
Integer *result = new Integer(
lhs.data * rhd.data);
return *result;
}

Who deletes?
The caller.
What about the following
use?
Integer a(1), b(2), c(3),
d(3);
Integer e =
a*b*c*d;
79

Overloading Unary Operators


Typically methods implementing unary
operators will not have any argument.
Exceptions:
post increment and post decrement operators.
As there are two operators with the same symbol
++, the name of the function is the the same.
Prototype for pre increment function:
void operator ++ ( );

Prototype for post increment function:

Jan-Feb 2016

void operator ++ (int a);

80

Operator Overloading Facts


Some operators can not be implemented as
global(friend) functions.
=, [] etc.

Some Operators cannot be overloaded


::,.*.?:,., sizeof() etc.

Precedence or arity of an operator cannot be


changed by overloading an operator.
Conditional Operators like &&, ||, comma
operator should not be overloaded.

Jan-Feb 2016

81

Friends vs Methods
Members are better in terms of restriction of
scope which results in efficient searching for
best function to resolve overloading.
Members will not help if the left hand side of the
operator is not of the class type.
String s1 = abc + s2; // may be wrong

In case of overloading stream operators, we


need friend due to the reason stated above.
Resolving in case of a conflict between friend
and method.
Jan-Feb 2016

82

Returning const from a function


Consider the following definition
const Rational & operator * (const Rational & lhs,
const Rational & rhs);

If the function returns a non-const, the


following is valid.
Rational a, b, c;
(a * b) = c;

Retuning const ensures that overloaded * is


compatible with the same operator on built-in
types.
Jan-Feb 2016

83

Overloading using const


Class String {
public:
char & operator [ ] (int pos)
{ return data[pos]; }
const char & operator [ ] (int pos)
{ return data[pos]; }
private:
char * data;

Jan-Feb 2016

String s1 = Hello;
cout << s[0];
// fine
s[0] = x;
// fine
const String cs = World;
cout << s[0];
// fine
s[0] = x;
// Error!!!

84

Bit-wise const vs. Conceptual


const
What should a constant member
function preserve?
Bit-wise const-ness
Conceptual const-ness

Bit-wise const member functions may


become unsafe.
Conceptual const member function may
need to change some bits of the object
mutable keyword.
Jan-Feb 2016

85

Object-Oriented Programming in C++

INHERITANCE
Jan-Feb 2016

86

Topics
Fundamentals of Inheritance
protected Access Specifier
Initialization
Virtual Functions

Jan-Feb 2016

87

Reusability
Reuse an already tried and tested code
Advantages:
Reduces cost & development time.
Improves quality

C Style Code Reuse


Library Function
Disadvantage: Reuse cannot be customized

C++ Style Reuse:


Inheritance
Composition

Jan-Feb 2016

88

Basics of C++ Inheritance


If a class A is derived from another class B then
A is called the derived/sub class and B is called
the base/super class.
All (?) data members and methods of the base
class are immediately available to the derived
class.
Thus, the derived class gets the behavior of the
base class
The derived class may extend the state and
behavior of the base class by adding more
attributes and methods.
Jan-Feb 2016

89

Accessibility of Base Class


Members
What happens to the access specifier of the
members of the base class when they are
derived?
Depends on the mode of derivation.

In public inheritance, private members of the


base class become private members of the
derived class and public members of the base
class become public members of the derived
class
However, private members of the base class
are not directly accessible to the members in
the derived class.
Jan-Feb 2016

90

Object Layout in Inheritance


Assume the
following class
hierarchy
class C: public B
{ .. };
class B: public A
{ .. };
class A
{ .. };
Jan-Feb 2016

Layout for an object


of type C

A-Part Data Member


B-Part Data Member
C-Part Data Member

91

protected Members
private data members of the base class
cannot be directly accessed by the
methods of the derived class.
However, it is important for the derived
class to have more accessibility to the
members of the base class than other
classes or functions.
If a member is protected then it is
directly accessible to the methods of the
derived class.
Jan-Feb 2016

92

Syntax of Inheritance
An example
class Employee {
protected:
float basic;
long id;
public:
Employee(long id);
float getSalary();
};
class Manager : public Employee {
protected:
Employee *supervised[10];
int numberOfPeopleManaged;
public:
Manager(Id, n);
float getSalary();
void printSupervisedEmployeeId();
}
Jan-Feb 2016

93

Order of Constructor Calls


The constructor of the derived class is
responsible for initializing the state of the
derived object.
The derived object contains attributes which
are inherited by the derived class.
The constructor of the derived class calls an
appropriate constructor of the base class
Therefore, the constructor of the base class is
executed first and then the constructor of the
derived class is executed.

Jan-Feb 2016

94

Example of Derived Class


Constructor
Employee::Employee(long id)
{
this->id = id;
}
Manager::Manager(long id, int n) : Employee(id)
{
numberOfPeopleManaged = n;
}

Jan-Feb 2016

95

Order of Destructor Calls


The destructor of the derived class is
responsible for cleaning up the state of
the derived object.
The derived object contains attributes
which are inherited by the derived class.
The destructor of the derived class calls
the destructor of the base class
Therefore, the destructor of the base
class is executed first and then the
destructor of the derived class is
executed.
Jan-Feb 2016

96

Casting
Derived class pointer can be implicitly
cast to a base class pointer
Manager m;
Employee *e = &m; // Employee *e = (Employee *)(&m);

Only base class part of the derived object


can be seen through the base pointer.
e-> printSupervisedEmployeeId(); //error

Jan-Feb 2016

97

Casting
A Base class pointer cannot be implicitly
cast to a derived class pointer
Manager *pM; pM = e; //error
pM = (Manager *)e; //ok
Down casting may be dangerous

Jan-Feb 2016

98

Static vs. Dynamic Binding


Binding refers to associate a type to a
name.
Consider the following example:
Manager m; Employee *e = &m;
e->getSalary(); //Which getSalary? Employee or Manager?

e is declared as a pointer to Employee

Jan-Feb 2016

99

Static vs. Dynamic Binding


Continue on the example:
Manager m; Employee *e = &m;
e->getSalary(); //Which getSalary? Employee or Manager?

In the example however, it makes more sense to


mean getSalary of the Manager class.
We need a dynamic binding of e so that the type
of e may be set at run time by pointer to the
type of the actual object
This is also called late binding

Jan-Feb 2016

100

Virtual Functions
In C++, dynamic binding is made
possible only for pointer & reference
data types and for methods that are
declared as virtual in the base class.
If a method is declared as virtual, it
can be overridden in the derived class.
If a method is not virtual and it is redefined in the derived class then the
latter definition hides the former one.
Jan-Feb 2016

101

Virtual Function: Example


class X{

class Y: public X{

public:

public:

int f(){ return 2; }

int f(){ return 4;}

virtual int g(){ return 3;}

int g(){ return 6;}

};

};

main() {
Y a;
int i, j , k, m;

Output will be 2 4 6 6

X *b = &a;
i = b->f(); j = a.f();
k = b->g(); m = a.g();
printf(%d %d %d %d\n, i, j, k, m);
}
Jan-Feb 2016

102

Redefining a Non-Virtual
Function
Simply do not do that.
class X() {

class Y : public X {

protected:

protected:

void f();
};

void f();
};

int main() {
Y y1;
Y *pY; X *pX;
pX = &y1;
pX->f(); // f as defined in X will be called
pY = &y1;
pY->f(); // f as defined in Y will be called
}
Jan-Feb 2016

103

Virtual Function Table


If a class has a virtual
function, then each
instance of that class
contains a space to store
a pointer to the actual
definition of that function.
During object creation,
the actual address of the
function is assigned to
the function pointer.

Jan-Feb 2016

Y is derived from X, which


has a virtual function.
X-part-data
X-part-virtual-function-ptr
Y-part-data

Actual definition of
the virtual function

104

Abstract Class
Pure Virtual Function
A virtual function may be assigned to NULL meaning that
this function is declared but not defined in a class.
Definition of such a class is incomplete.

A class with one or more pure virtual function is


called an abstract class.
Abstract class cannot be instantiated.
Abstract class define a contract or interface to be
used by the user of the class library and to be
implemented by the developer of the class library.
Jan-Feb 2016

105

Virtual Destructor
Constructors cannot be virtual
For a base class which has been derived from,
the destructor must be declared virtual.
Occasionally we create a derived object and store
it using a pointer to Base class such as
Base *pBase = new Derived(/*arguments*/);

If we destroy this object using delete pBase


then two destructors need to be called.
If the destructor in the Base class is not declared
virtual then the destructor of the Derived class
will not be automatically called in this example.
Jan-Feb 2016

106

Inheritance Example:
Polymorphic Array
Consider an abstract base class Shape which
contains a pure virtual function CalculateArea.
Suppose three classes Triangle, Rectangle and
Circle derived from Shape.
Consider a main function that creates different
Shape objects and store them in an array.
If in a for loop the function calculateArea is
called on all objects in the array, we see
dynamic binding in use.

Jan-Feb 2016

107

Polymorphic Array: Class


Definitions
class Shape {

class Circle : public Shape() {

public:
0;

private:

virtual double calculateArea() =

Point centre;
double radius;

};

Circle(double x_centre,

class triangle : public Shape() {

double y_centre,

private:

double r);,

Point a, b, c;

public:

Triangle(double x_a, double y_a,


double x_b, double y_b,
double x_c, double y_c);

double calculateArea();
};

public:
double calculateArea();
};
Jan-Feb 2016

108

Polymorphic Array: main


function
int i,

int main() {

double x_a, x_b, x_c, y_a, y_b, y_c;

Shape *pArr = NULL;

while (1) { int j = 0;

int n = getInput(pArr);

scanf(%d, &i);

for (int i = 0; i < n; i++) {

switch (i) {

double area =

case 0: break;

Shape[i]->calculateArea();

case 1:

printf (%d %lf \n, i, area);

scanf(%f%f%f%f%f%f, &x_a,

&y_a, &x_b, &y_b, &x_c, &y_c);

pArr[j++] = new Triangle(&x_a,

int getInput(Shape *pArr) {

&y_a, &x_b, &y_b, &x_c, &y_c);

printf(Which Shape do you want to


create?\n);

break;

printf(Write 1 for triangle, 2 for


rectangle, 3 for circle and 0 to
quit\n);

..
}
}
}

Jan-Feb 2016

109

Inheritance: Benefits

Code Sharing/Reuse
Consistency of Interface
Construction of Software Components
Rapid Prototyping
Information Hiding

Jan-Feb 2016

110

Inheritance: Cost

Execution Speed
Program Size
Message Passing Overhead
Program Complexity

Jan-Feb 2016

111

Inheritance: Limitations
operator= cannot be inherited
Can be used to assign objects of the same
type only

Copy Constructor cannot be inherited


Static members are inherited in a
derived class
Static members cannot be virtual
If you redefine a static member function, all
other overloaded functions in the base class
are hidden
Jan-Feb 2016

112

Inheritance Notes
Constructors cannot be virtual
Calling a virtual function from within a
constructor does not have the desired effect.
The following code is buggy. Tell why.
void f(Base *b) {

int main() {

b[0].f(); b[1].f();

Derived d[10];

f(d);
}

Derived is publicly derived from Base.


Class Base has a virtual function f which is
redefined in Derived.
Jan-Feb 2016

113

Default Parameter & Virtual


Function
Do not change the default parameter in a
redefined virtual function
class X() {

class Y : public X {

protected:

protected:

virtual void f(int i = 10);


};

virtual void f(int i =20);


};

int main() {
Y y1;
Y *pY; X *pX;
pX = &y1;
pX->f(); // f with value of i as 10 will be called
pY = &y1;
pY->f(); // f with value of i as 20 will be called
}
Jan-Feb 2016

114

Is an Ostrich a Bird
Suppose there is a base class Bird
a virtual method fly returns altitude > 0.

A class Ostrich is derived from Bird.


fly method has to be redefined as an
empty function.

Leads to a logical dilemma.


Can an overridden method be empty?
Can an overridden method throw
exceptions?
Jan-Feb 2016

115

Is a Circle an Ellipse?
Circle is a special type of ellipse.
Let Circle be derived from Ellipse.
Suppose that Ellipse has a method
setSize(x,y).
Also suppose that there is a function sample as
defined below.
sample (Ellipse &e) { e. setSize(10,20); . }
If sample is called on a circle, strange things
happen!
Subset is not substitutable!!
Jan-Feb 2016

116

Should a Stack inherit from a


List?
Probably Not!
If List is the base class of Stack
Methods such as push, pop etc. are to be
defined (at least as pure virtual) in the
List class.
All members of List must have (even a
trivial) implementation in Stack.

A Stack has a List.


Jan-Feb 2016

117

Multi-level Inheritance
Suppose that C is derived from B and B is
derived from A.
Suppose that a method, f, in A is virtual.
If f is redefined in B then f is virtual even if
the keyword virtual does not precede the
declaration/definition in the derived class.
It is advisable to explicitly write virtual in
front of the definition of f in B as, otherwise,
an implementer of C may think that f is not a
virtual method.

Jan-Feb 2016

118

Inheritance & Code Reuse


Suppose that C and B and are derived from A.
Both C and B contain a function f ; therefore, f
is made a virtual (not pure) function in A.
This is bad.

A new class D is required to be derived from A


later.
f in D is different than A.
Interfaces should not have implementation.

Jan-Feb 2016

119

private Inheritance
If B is privately derived from A then private,
protected and public members of A become
private members of B. However, private
members of A are not directly accessible to B.
Thus, even if C is publicly derived from B then
no member of A is accessible to C.
Functions which may access members of A in B
are
Methods of class B
Friend functions of class B.

Jan-Feb 2016

120

protected Inheritance
If B is protectedly derived from A then,
protected and public members of A become
protected members of B. However, private
members of A remain private in B and are not
directly accessible to B.
Functions which may access members of A in B
are
Methods of class B
Friend functions of class B.
Methods in classes publicly derived from B
Friend functions of classes publicly derived from B
Jan-Feb 2016

121

Private Inheritance: Implications


public Inheritance models is a
private inheritance models is implemented in
terms of
Assume two classes, Set and List.
Set contains unique elements while List may contain
duplicate elements.
Thus Set is not a List
But a Set can use the code of the List class as a Set
can be implemented in terms of a list.
Users of the class Set should not have an access to the
List behavior even to create further derived classes
Jan-Feb 2016

122

Object-Oriented Programming in C++

TYPE CASTING
Jan-Feb 2016

123

Type Casting
Why casting?
Casts are used to convert the type of an object,
expression, function argument, or return value to
that of another type.

(Silent) Implicit conversions.


The standard C++ conversions and user-defined
conversions

Explicit conversions.
type is needed for an expression that cannot be
obtained through an implicit conversion
more than one standard conversion creates an
ambiguous situation
Jan-Feb 2016

124

Type Casting
To perform a type cast, the compiler
allocates temporary storage
Initializes temporary with value being cast
float f (int i,int j) {
return (float ) i / j;
}
// compiler generates:
float f (int i, int j) {
float temp_I = i, temp_j = j;
return temp_i / temp_j;
}
Jan-Feb 2016

125

Automatic (Implicit) Conversion


Automatic conversions from one type to
other may be extremely convenient.
Automatic conversions (either
conversion operators or single argument
non-explicit constructors) are unsafe as
well.
can interfere with overload resolutions.
can silently let wrong code compile cleanly.
String s1, s2, s3;
s3 = s2 s1; // Though - is not overloaded in String
Jan-Feb 2016

126

Casting to User Defined Type


Constructors help
The following statement is not an error
even when an appropriate assignment
operator is not defined but an
appropriate constructor is defined
(which constructor?)
String s1; s1 = example;
Jan-Feb 2016

127

Casting to User Defined Type


The assignment statement is
converted to the following
s1 = String(example);

Lots of temporary objects are created.


Even the following statement is
correct:
s1 = s2 + abc + def;
Jan-Feb 2016

128

Ambiguities: Example
Overuse of such
casting may lead to
ambiguities as
illustrated in the
following example
/* ambig.cpp */
#include string.h
class example {
public:
example(const char *) { } ;
};
void

Jan-Feb 2016

f1 (const String & )


{
}
void
f1 (const example & )
{
}
int
main ( )
{
//
f1 (hello, world) ; is ambiguous
f1 ((String) hello world );
f1 ((example) hello world );
//
or provide void f1 (const char *)
return 0;
}

129

Ambiguity: Example
class B;
class A {
public:
A (const B &);
...
};

Which one to use for


casting?
Constructor in A OR
Cast Operator in B

class B {
public:
operator A () const;
};
void f(const A &);
B b;
f(b); //Error - Ambiguous

Jan-Feb 2016

130

Casting from Class Types


To cast a user defined type to some other type,
type casting operator is to be defined explicitly.
To convert to a type, say <type>, the following
function operator <type> is to be defined.
Such functions do not have an explicit return
type and do not take any argument
(NATURALLY!).
The following example illustrates how a string
object can be cast to a char * by defining a
function operator char *() .

Jan-Feb 2016

131

Example of user defined cast


const int max_string_length = 128;
class String {
public:
String ( ) :
String (const String & ) ;
String (const char *);
~String ( ) ;
String & operator = (const String & )
;
operator const char * ( ) const ;
int length ( ) const ;
int read ( ) ;
void print ( ) const ;
.
.
private:
char text [max_string_length+1]
};
Jan-Feb 2016

void operator-(const String &, const


String &);
int main ( ) {
int fd;
String filename = tmp/test;
// cast filename to type const char *
fd = open (filename, O_WRONLY |
O_CREAT, 0666);
write (fd, test, 4);
close (fd);
// not legal, since we can cast only
to const char *
// strcpy (filename, zbc);
String name = Zaphod
Beeblebrox;
name Beeblebrox; // is now
ambiguous.
return 0 ;
}
132

Avoiding Ambiguities
const int max_string_length = 128;
class String {
public:
String ( ) ;
String (const String & ) ;
String (const char *);
~ String ( ) ;
String & operator = (const String &
);
const char *as_char_pointer ( )
const;
int length ( ) const;
int read ( );
void print ( ) const;
...
private:
char text [max_string_length+1];
};

Jan-Feb 2016

void operator-(const String &, const


String &);
int main ( ) {
int fd;
String filename = /tmp/test;
// convert filename to type char *
fd = open
(filename.as_char_pointer ( ),
O_WRONLY | O_CREAT, 0666);
write (fd, test, 4);
close (fd);
// not legal
// strcpy (filename.as_char_pointer (
), zbc);
String name = Zaphod
Beeblebrox;
name Beeblebrox; // is no longer
ambiguous
return 0;
}
133

Casting Pointers & References


Casting a value:
float f_var = 3.14;
cout << (int) f_var;
creates a temporary object
does not violate data encapsulation

Casting a pointer or reference


cout << *(( int *) &f_var);
cout << (int &) f_var;
Re-interprets representation of object
Violates data encapsulation
Jan-Feb 2016

134

C++ casts
There are four cast operators in C++

const_cast
static_cast
reinterpret_cast
dynamic_cast

Only dynamic_cast is not equivalent


to a C-style cast

Jan-Feb 2016

135

Prefer C++ casts to C-style


casts
Type conversions of any kind (either explicit
via casts or implicit by compilers) often lead to
code that is executed at runtime.
Easier to identify (can grep)
C-style casts do not have a usage semantics
that compilers may use.
More narrowly specified purpose for each
specified cast; compilers can diagnose user
errors.
Some casts are performed safely at run-time.

Jan-Feb 2016

136

const_cast operator
Syntax:

const_cast < type-id > ( expression )

The const_cast operator can be used to remove the


const, volatile attribute(s) from a class.
A pointer to any object type can be explicitly converted
to a type that is identical except for the const, volatile
qualifiers. Applying on pointers and references, the
result will refer to the original object.
The const_cast operator cannot be used to directly
override a constant variable's constant status.

Jan-Feb 2016

137

const_cast operator: Example


Example
#include <iostream>
class CCTest {
public:
void setNumber( int );
void printNumber() const;
private:
int number;
};
void CCTest::setNumber( int num )
{ number = num; }
void CCTest::printNumber() const {
cout << "\nBefore: " << number;
const_cast< CCTest * >( this )>number--;
cout << "\nAfter: " << number;
}
Jan-Feb 2016

int main() {
CCTest X;
X.setNumber( 8 );
X.printNumber();
}

On the line containing the


const_cast, the data type of
the this pointer is const CCTest
*. The const_cast operator
changes the data type of the
this pointer to CCTest *,
allowing the member number
to be modified. The cast lasts
only for the remainder of the
line on which it appears.
138

Usage of const
The example of the previous slide is not
the best usage of const.
The member number should be mutable
instead.

When one has a const object and has to


pass it to some function that takes a
non-const parameter and it is known
that the function does not modify that
parameter then casting away const-ness
is both useful and safe.
Jan-Feb 2016

139

Guidelines for const


const is a powerful tool for writing safer code;
use it as much as possible but no more.
Do not use const pass-by-value parameters in
function declarations. This is not useful and
misleading at best.
When returning a user defined type, prefer
returning a const value.
Do not return handles to internal data from a
const member function.

Jan-Feb 2016

140

static_cast operator
Syntax:
static_cast < type-id > ( expression )

The static_cast operator converts expression to


the type of type-id based solely on the types
present in the expression.
static_cast has basically same power, meaning
and restrictions as C-style cast. It cannot be
used to convert a struct into an int or a double
into a pointer.

Jan-Feb 2016

141

static_cast operator
In general, a complete type can be converted
to another type so long as some conversion
sequence is provided by the language.
may also use static_cast to convert any
expression to a void, in which case the value of
the expression is discarded.
It cannot change the const-ness of an
expression.

Jan-Feb 2016

142

static_cast: Example
Example:
class B { ... };
class D:public B { ... };
void f(B* pb, D* pd){
D* pd2 =
static_cast<D*>(pb);
// not safe, pb may point to
just B
B* pb2 = static_cast<B*>(pd);
// safe conversion
...
}.

Jan-Feb 2016

The static_cast operator


can be used for
operations such as
converting a base class
pointer to a derived class
pointer . Such
conversions are not
always safe since no runtime type check is made
to ensure the safety of
the conversion.For such
conversions dynamic_cast
should be used.

143

C-style casts VS static-cast


class Base {
public: Base() : _data(999) {}
int Data() const {
return _data;
}
private: int _data;
};
class Derived : private Base {
public: Derived () : Base() {}
};
Derived *d1 = new Derived;

Jan-Feb 2016

The following C-style


code works even if .
int i = d1->Data(); //Error!
Base* b1 = (Base*) d1;
int i = b1->Data(); // works!
Base *b2 = static_cast<Base
*>(d1); //Error!

The old C-style casts let


us cast from one
incomplete type to
another! static_cast does
not let you do that.

144

reinterpret_cast operator
Syntax:
reinterpret_cast < type-id > ( expression )

The reinterpret_cast operator allows any


pointer to be converted into any other pointer
type. It also allows any integral type to be
converted into any pointer type and vice versa.
The reinterpret_cast operator can be used for
conversions such as char* to int*, or
One_class* to Unrelated_class*, which are
inherently unsafe.
Jan-Feb 2016

145

reinterpret_cast operator
The result of a reinterpret_cast cannot safely be used for
anything other than being cast back to its original type.
Other uses are, at best, non-portable.
The reinterpret_cast operator cannot cast away the
const, volatile attributes.
One practical use of reinterpret_cast is in a hash
function, which maps a value to an index in such a way
that two distinct values rarely end up with the same
index.
Reinterpret_cast should rarely be used in a C++
program

Jan-Feb 2016

146

reinterpret_cast: Example
Example
#include <iostream>
unsigned short Hash( void *p ){
// Returns a hash code based on an
address
unsigned int val =
reinterpret_cast<unsigned int>( p
);
return ( unsigned short )( val ^ (val
>> 16));
}
int main(){
int a[20];
for ( int i = 0; i < 20; i++ )
cout << Hash( a + i ) << endl;
}

Jan-Feb 2016

The reinterpret_cast
allows the pointer to be
treated as an integral
type. The result is then
bit-shifted and XORed
with itself to produce a
unique index (unique to
a high degree of
probability). The index is
then truncated by a
standard C-style cast to
the return type of the
function.

147

Usage of casts
class A { public: virtual ~A(); };
class B : private virtual A { };
class C : public A { };
class D : public B, public C { };
A a1; B b1; C c1; D d1;
const A a2;
const A& ra1 = a1;
const A& ra2 = a2;
char c;

A *pa = (A *)&ra1;
Use const_cast

B * pb = (B*)&c1;
Use reinterpret_cast

A *pa = (A*)&a2;
Cannot be expressed
in a new-style cast.

void *pv = &b1;


B *pb = (B*)(pv);
Use static_cast
instead;

Jan-Feb 2016

148

Avoid Unnecessary Cast


Look at the cast and comment
class SpecialWindow: public Window { // derived class
public:
virtual void onResize() { // derived onResize impl;
static_cast<Window>(*this).onResize(); // cast *this to Window,
// then call its onResize;
// this doesnt work!
... // do SpecialWindow} // specific stuff
...
};

Jan-Feb 2016

149

type_info class
The type_info class describes type information
generated within the program by the compiler. The
entire definition of this class is implementation
dependent but the following features of this class is
standardized.
Objects of this class effectively store a pointer to a
name for the type. The type_info class also stores an
encoded value suitable for comparing two types for
equality or collating order.
The operators == and != are overloaded and can
be used to compare for equality and inequality with
other type_info objects, respectively.

Jan-Feb 2016

150

type_info class
Features of type_info class (contd):
The name member function returns a const char*
to a null-terminated string representing the humanreadable name of the type. The memory pointed to is
cached and should never be directly deallocated.

Type information is generated for polymorphic


classes only if the /GR (Enable Run-Time Type
Information) compiler option is specified.

Jan-Feb 2016

151

typeid operator
Syntax:
typeid( type-id )

OR

typeid(expression)

The typeid operator allows the type of an object


to be determined at run time.
The result of typeid is a const type_info&.
The typeid operator does a run-time check when
applied to an l-value of a polymorphic class
type, where the true type of the object cannot
be determined by the static information
provided. Such cases are: a reference/ Pointer
Jan-Feb 2016

152

typeid operator
When the operand of typeid is of a nonpolymorphic class type, the result is the type of
the operand not the type of the underlying
object.
type-id may be used with operands of built-in
types.

Jan-Feb 2016

153

typeid:Example
The expression usually
points to a polymorphic
type (a class with virtual
functions).
The pointer must be dereferenced so that the
object it points to is used.
Without de-referencing the
pointer, the result will be
the type_info for the
pointer, not pointee
Example

int main(){
Derived* pd = new Derived;
Base* pb = pd;
cout << typeid( pb ).name() << endl;
//prints "class Base *
cout << typeid( *pb ).name() <<
endl; //prints "class Derived"
cout << typeid( pd ).name() << endl;
//prints "class Derived *"
cout << typeid( *pd ).name() <<
endl; //prints "class Derived"
delete pd;
}

#include <iostream>
#include <typeinfo.h>
class Base {
public: virtual void vvfunc() {} }
class Derived : public Base {};
Jan-Feb 2016

154

dynamic_cast operator
Syntax:
dynamic_cast<typeid> (expression)

The expression
dynamic_cast<typeid>( expression)
converts the
operand expression
to an object of type
type-id.
It is used for downcasting.
Jan-Feb 2016

Example
class B { ... };
class C : public B { ... };
class D : public C { ... };
void f(D* pd){
C* pc = dynamic_cast<C*>(pd);
// ok: C is a direct base class, pc points to
C subobject of pd
B* pb = dynamic_cast<B*>(pd);
// ok: B is an indirect base class , pb
points to B subobject of pd
...
}

155

dynamic_cast: Example
Example:
class B { ... };
class D : public B { ... };
void f(){
B* pb = new D;
// unclear but ok
B* pb2 = new B;
D* pd = dynamic_cast<D*>(pb);
// ok: pb actually points to a D
...
D* pd2 = dynamic_cast<D*>(pb2); // pb2 points to a B not a D the cast is bad
so pd2 is NULL
...
}

Jan-Feb 2016

156

dynamic_cast
If dynamic_cast to a pointer type fails, the result of the
dynamic_cast is null; if dynamic_cast to a reference type
fails, an exception is thrown.
dynamic_cast is performed at run-time.
dynamic_cast can be used only for pointer or reference
types to navigate a class hierarchy. The dynamic_cast
operator can be used to cast from a derived class pointer
to a base class pointer, cast a derived class pointer to
another derived (sibling) class pointer, or cast a base
class pointer to a derived class pointer. Each of these
conversions may also be applied to references.

Jan-Feb 2016

157

dynamic_cast
dynamic_cast operator cannot be used for built-in types.
All of the derived-to-base conversions are performed
using the static (compile-time) type information. These
conversions may, therefore, be performed on both nonpolymorphic and polymorphic types. These conversions
will produce the same result if they are converted using a
static_cast. However, even these results may be wrong in
the presence of multiple inheritance.
dynamic_cast is strongly recommended to be applied on
polymorphic types.

Jan-Feb 2016

158

Cost of dynamic_cast
The pointer to the type_info object of a class is
stored in the vtbl array of the class.
Thus, the space cost for RTTI is an additional
entry in each class vtbl plus the cost of storage
for the type_info object for each class.
Size of the objects do not increase for RTTI
operations.
Cost of RTTI at run time is similar to the cost
of calling a virtual function; cost of calling a
virtual function is the same as the cost of
calling a function through a function pointer.
Jan-Feb 2016

159

Object Oriented Programming in C++

EXCEPTIONS
Jan-Feb 2016

160

Topics
Basic Concept of Exceptions
try-catch block in C++
Semantics of throw

Jan-Feb 2016

161

Error Handling in C++


Error Condition Handling - C Style
via return value
return statement is dedicated for passing
error conditions

by output parameter
normal and abnormal control flow
tend to mix
Reusing code for error handling is
difficult.
Jan-Feb 2016

162

Error Handling in C++


Error Condition Handling - C++
Style
On error condition an exception object
is created and thrown.
A function catches exception objects
generated from the function it calls in
a distinct control flow.
Similar Exception objects can enjoy
benefits of inheritance.
Jan-Feb 2016

163

C-Style Error Handling


int
Calculator::divide (int i)
{
if (i == 0)
{
// what do we do?
}
else
{
value /= i;
}
return value;
}

Jan-Feb 2016

A Calculator need to
handle divide by zero
Could set value to NAN
But, program would need
to check for special value
(and might ignore)

Could return 1
Again program could
ignore
Might be a valid return
value

164

try and catch


A function has its usual prototype and it may
throw a number of exceptions on detecting
several error condition.
try block encloses code that has usual flow of
control and can potentially throw exceptions
catch block can occur after a try block or
another catch block
catch blocks can catch and handle exceptions
of different types

Jan-Feb 2016

165

Exception Object and throw


Exception object is just another object having
members (attributes and methods) suitable to
model the state and behavior of an object
representing an error condition.
Whenever an error condition is detected, a
suitable Exception object is thrown. Semantics
of throw is as follows.
Creation of an object (function of new)
passing control from this function to the caller
function (similar to return)
Unlike return, throw initiates unwinding of the call
stack till the exception is handled.
Jan-Feb 2016

166

Example of Exception Handling


in C++
class DivideByZero {

int main (int argc, char **argv) {

private:

int i = 0;

int dividend;

Calculator c;

public:

try {

print() {

c.divide (0);

cout << dividend << is divided by zero


<<endl;

cout << c.getValue ();


}

catch (DivideByZero& ext) {

DivideByZero(int d) { dividend = d; }

ex.print();

};

return 1;

int Calculator::divide(int i) throws


DivideByZero {
if (i ==0)
throw DivideByZero(value);

}
return 0;
}

value /= i;
return value;
}
Jan-Feb 2016

167

Example of Exception Handling


in C++
class DivideByZero { private:

int main (int argc, char **argv) {


int i = 0;

int dividend;
public: print() {

Calculator c;

cout << dividend << is divided


by zero <<endl;

try {
c.divide (0);

cout <<

c.getValue ();

DivideByZero(int d)

{ dividend = d; }

catch (DivideByZero& ext) {

};

ex.print();

int Calculator::divide(int i)
throws DivideByZero {

return 1;
}

if (i ==0)
throw DivideByZero(value);

return 0;
}

value /= i;
return value;
}

Jan-Feb 2016

168

Details of throw
Normal program control flow is halted
At the point where an exception is thrown

The program call stack unwinds


Stack frame for each function up call chain is popped
Stack variables in each popped frame are destroyed
Until an enclosing try/catch scope is reached where
the type of exception thrown is caught.

Control passes to first matching catch block


Can handle the exception and continue
Can free resources and re-throw

Jan-Feb 2016

169

More on try and catch


Whenever a function is called in a try block,
the catch blocks to be examined after the try
block are known as the extended prototype of
a function includes the throw clauses.
catch blocks after a try block are examined in
order when an exception is thrown from a
function called in the try block.
Parentheses for each catch block has semantics
of a function argument declaration

Jan-Feb 2016

170

Exception Specifications
// can throw anything
void
Calculator::subtract
(int i);
// promises not to throw
void
Calculator::add
(int i) throw ();
// promises to only throw int
void
Calculator::divide

Make promises to the caller


Allow stronger type checking
enforced by the compiler
By default, a function can throw
anything it wants
A throw clause in the signature

Limits what a function can throw


A promise to the calling function

A throw clause with no types

Promises nothing will be thrown

Can list multiple types

Comma separated

(int i) throw (int);


Jan-Feb 2016

171

Exception Specifications
// can throw anything
void
Calculator::subtract
(int i);

// promises not to throw


void
Calculator::add
(int i) throw ();

Make promises to the caller


Allow stronger type checking
enforced by the compiler
By default, a function can throw
anything it wants
A throw clause in the signature

Limits what a function can throw


A promise to the calling function

A throw clause with no types


// promises to only throw
int
void
Calculator::divide

Promises nothing will be thrown

Can list multiple types

Comma separated

(int i) throw (int);


Jan-Feb 2016

172

Stack Frame
automatic variables
parameters
previous frame pointer
return address

Jan-Feb 2016

g++ -s gives assembler output that


can be used to deduce exact structure
for a given platform
In general, the overall structure is
common
A chunk of memory representing a
function call
Allocated on program call stack at
runtime. Contains:

The frame pointer

The return address for the call (i.e., where


it was called from)

Parameters passed to the function

Automatic (stack) variables for the function


173

Illustrating the Call Stack


int main (int argc, char **argv) {

int i = 0;
Calculator c;
try {
c.divide (0);
cout <<
c.get_value ();
}

Stack frame for function main

Note that parameters are


initialized at frame creation
Variables are not necessarily
initialized at frame creation

catch (int) {
return 1;

Jan-Feb 2016

May occur later in called


function

}
return 0;

Allocated on program call stack


With stack variables i and c
With parameters argc and argv

value_

main
argc

argv
174

Illustrating the Call Stack, cont.


int main (int argc, char **argv) {
int i = 0;

Enter function main

Calculator c;
try {

Stack variable initialized to


0

c.divide (0);
cout <<
c.get_value ();
}
catch (int) {
return 1;

}
return 0;
}

Jan-Feb 2016

value_

main
argc

argv
175

Illustrating the Call Stack, cont.


int main (int argc, char **argv) {
int i = 0;
try {
c.divide (0);
cout <<

c.get_value ();
catch (int) {

Call Default Constructor for c

Calculator c;

Allocate a new stack frame


No parameters or automatic variables for
that specific function
Params depend on function signature
declaration
Automatics depend on function body
definition

Calculator::
Calculator( )

this

return 1;

}
return 0;
}

Jan-Feb 2016

value_

main
argc

argv
176

Illustrating the Call Stack, cont.


Calculator::Calculator ()

: value_ (0)
{}

Enter function Calculator::Calculator ( )

void
Calculator::divide (int i) throw (int)

Member variable value_ of stack variable c


is initialized to zero

How do we know which value_ to set?

There may be multiple Calculator instances


Answer: implicit this parameter in stack
frame

{
if (i == 0) {
throw i;

Calculator::
Calculator()

this

} else {
value_ /= i;

}
cout << value_;
}
Jan-Feb 2016

value_

main
argc

argv
177

Illustrating the Call Stack, cont.


Calculator::Calculator ()
: value_ (0)
{
}

Return from function


Calculator::Calculator ( )
Deallocate the stack frame, return to
previous

void
Calculator::divide (int i) throw
(int) {
if (i == 0) {
throw i;
} else {
value_ /= i;
}
cout << value_;

main

value_

argc

argv

}
Jan-Feb 2016

178

Illustrating the Call Stack, cont.


int main (int argc, char **argv)

Call divide method on c

int i = 0;
Calculator c;
try {

Allocate a new stack frame


Contains parameters this and i
Copy address of current instance into
this
Copy value 0 into i

c.divide (0);

cout <<

void Calculator::
divide (int )

c.get_value ();

this

}
catch (int) {

return 1;
}
return 0;

value_

main
argc

argv

}
Jan-Feb 2016

179

Illustrating the Call Stack, cont.


Calculator::Calculator ()
: value_ (0)
{
}

Enter function Calculator::divide


(int)

void
Calculator::divide (int i) throw (int)
{
if (i == 0) {
throw i;
} else {
value_ /= i;
}
cout << value_;
}

Test i equal to 0 and take the true


branch
Throw integer i

void Calculator::
Calculator (int )

this
i

i
value_

main
argc

Jan-Feb 2016

argv
180

Illustrating the Call Stack, cont.


Calculator::Calculator ()
: value_ (0)
{
}
void
Calculator::divide (int i) throw
(int)
{
if (i == 0) {
throw i;
} else {
value_ /= i;
}
cout << value_;
}

Jan-Feb 2016

Thrown exception unwinds call stack


Notice control skips over cout statement
to end
Deallocate the stack frame, return to
previous
Return from function void
Calculator::divide ( )

value_

main
argc

argv
181

Illustrating the Call Stack, cont.


int main (int argc, char **argv)

{
int i = 0;
Calculator c;
try

{
c.divide (0);
cout << c.get_value ();
}
catch (int)
{
return 1;
}
return 0;
}

Weve reached an enclosing


try/catch scope

So stack unwinding stops

Control jumps to first matching


catch block

Again, skips over intervening cout


statement

value_

main
argc

Jan-Feb 2016

argv
182

More on catch
try {
// can throw an exception

Control jumps to first


matching catch block

}
catch (Derived &d) {
// ...

}
catch (Base &b) {
// ...

}
catch (...) // catch all...
{
// ...
}

Jan-Feb 2016

Order matters with


multiple possible matches
Especially with
inheritance-related
exception classes
Hint: put catch blocks for
derived exception classes
before catch blocks for
their respective base
classes
More specific catch before
more general catch
catch () catches any
type
183

A Few More on catch


try
{
// can throw an exception
}
catch (MyClass &e)
{
// ...
throw; // rethrows e
}
catch (int)
{
// ...
}
catch (...) // catch all...
{
// ...
}

Jan-Feb 2016

Notice catch-by-reference
for user defined types

More efficient

Only a reference propagates


Rather than entire object

More correct

Avoids class-slicing problem if


catch as base type, rethrow
Preserves polymorphism
More on this in later lectures

Can leave off variable


name

Unless catch block needs


to do something with the
instance that was caught
184

Object-Oriented Programming in C++

TEMPLATES
Jan-Feb 2016

185

What is a Template?
Templates are specifications of a
collection of functions or classes which
are parameterized by types.
Examples:
Function search, min etc..
The basic algorithms in these functions are the same
independent of types.
But, we need to write different versions of these
functions for strong type checking in C++.

Classes list, queue etc.


The data members and the methods are almost the
same for list of numbers, list of objects.
We need to define different classes, however.
Jan-Feb 2016

186

Function Template: An Example


void swap(int &i, int &j)
template<class X> void swap (X &one, X
&other)
{
{
int temp;
X temp;
temp = i;
temp = one;
i = j;
Type parameter
one = other;
j = temp;
Type parameter list
other = temp;
}
}
void swap(String &i, String &j)
{
Main() {
String temp;
int I=10, j=20;
temp = i;
swap(I, j);
i = j;
String s1(abc), s2(def);
j = temp;
swap(s1, s2);
}
}

Template instantiation
Jan-Feb 2016

187

Example
#include <iostream>
#include <string> using namespace std;
template <typename T>
inline T const& Max (T const& a, T const& b)
{ return a < b ? b:a; }
int main () {
int i = 39; int j = 20;
cout << "Max(i, j): " << Max(i, j) << endl;
double f1 = 13.5; double f2 = 20.7;
cout << "Max(f1, f2): " << Max(f1, f2) << endl;
string s1 = "Hello"; string s2 = "World";
cout << "Max(s1, s2): " << Max(s1, s2) << endl;
return 0;
}
Jan-Feb 2016

188

Example
#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <stdexcept> using namespace std;
template <class T>
class Stack {
private: vector<T> elems; // elements
public:
void push(T const&); // push element
void pop(); // pop element
T top() const; // return top element
bool empty() const { // return true if empty.
return elems.empty(); }
};
Jan-Feb 2016

189

Parameterized Functions
A function template
describes how a function should be built
supplies the definition of the function using some
arbitrary types, (as place holders),
a parameterized definition
can be considered the definition for a set of overloaded
versions of a function
is identified by the keyword template
followed by parameter identifiers
enclosed between < and > delimiters
noting they are
Jan-Feb 2016

class, (i.e. type), parameters


190

Template Non-type Parameter


It is an ordinary parameter
template <class T, int size> T min (T
(&x[size]));
When min is called, size is replaced with
a constant value known at compile time

The actual value for a non-type


parameter must be a constant
expression.
Jan-Feb 2016

191

typename
The key words class and typename have
almost the same meaning in a template
parameter
typename is also used to tell the compiler that
an expression is a type expression
template <class T> f (T x) {
T::name * p; // Is this a pointer declaration or multiplication?
}
template <class T> f (T x) {
typename T::name * p; // Is this a pointer declaration or
multiplication?
}
Jan-Feb 2016

192

Template Argument Deduction


Each item in the template parameter list is a
template argument
When a template function is invoked, the
values of the template arguments are
determined by seeing the types of the function
arguments
template <class T, int size> Type min( T(&x[size]));
int pval[9]; min(pval); //Error!!

Jan-Feb 2016

193

Template Argument Deduction


Three kinds of conversions are allowed.
L-value transformation (e.g., Array-to-pointer
conversion)
Qualification conversion
Conversion to a base class instantiation from a class
template

If the same template parameter are found for


more than one function argument, template
argument deduction from each function
argument must be the same

Jan-Feb 2016

194

Explicit Template Arguments


It is possible to override template argument
deduction mechanism and explicitly specify
the template arguments to be used.
template <class T> T min(T x, T y);
unsigned int ui; min (ui, 1024); //Error!!
min<unsigned int>(ui, 1024); // OK

Specifying return type generically is often a


problem.
template <class T, class U> ??? sum(T x, U y);
sum(ch, ui) returns U; sum (ui, ch) returns T
template < class R, class T, class U> R sum(T x, U
y)
min<int>(i, a);
Jan-Feb 2016

195

Template Explicit Specialization


Some times, a template may not be
suitable for all types.
The following template is not good for
char *
template <class T> T min(T x, T y)
{ return (x < y) ? x : y); }

Define the function explicitly for char *


template<> char * min <char *>(char *x, char *y)
{ return ((strcmp(x, y) < 0) ? x : y); }

Jan-Feb 2016

196

A List Template Class


template<class T>
class List {
public :
List ();
virtual ~List ();
int put (const T &val);
T *unput ();
T *get ();
int unget (const T &val);
T *find(const T &val);
int length ();
private:
struct Node {
Node *next_item;
T *list_item;
} *beg_ptr; *end_ptr;
int how_many;
};

Jan-Feb 2016

template<class T> int List<T>:: put (const T


&val)
{
Node *tmp_ptr = new Node;
if (tmp_ptr && (tmp_ptr->list_item = new
T (val) ) ) {
tmp_ptr->next_item = 0;
if (end_ptr)
end_ptr->next_item = tmp_ptr;
else
beg_ptr = tmp_ptr;
end_ptr = tmp_ptr;
how_many++;
return 1;
}
else
return 0;
}

197

Using a Template Class


int main () {
register int i, *iptr;
String *sptr;
char *somedata [] = {one, two, three, four,
five, six, seven, eight, nine, ten};
List<int> ii;
List<String> is;
for (i = 1; i <=10; i++) { ii.put(i); }
cout << The List<int> contains ;
cout << ii.length () << items\n ;
return 0;
}

Jan-Feb 2016

198

Parameterized Class
A class template
describes how a class should be built
Supplies the class description and the
definition of the member functions using some
arbitrary type name, (as a place holder).
is a parameterized type with
parameterized member functions

Jan-Feb 2016

199

Parameterized Class
can be considered the definition for an
unbounded set of class types
is identified by the keyword template
followed by parameter identifiers
enclosed between < and > delimiters
noting they are class, (i.e. type),
parameters
is often used for container classes

Jan-Feb 2016

200

Parameter Requirements
Parameter Types
may be of any type, (including user defined
types)
may be parameterized types, (i.e. templates)

MUST

support the methods used by the


template functions:
what are the required constructors ?
the required operator functions ?
What are the necessary defining
operations ?

Jan-Feb 2016

201

Class Template Instantiation


Class Template is instantiated only when it is
required.

Matrix is a class template


Matrix m; //error
Matrix *pm; // OK
void inverse (Matrix & m); //OK

Class template is instantiated before


An object is defined with class template instantiation
If a pointer or a reference is de-referenced (e.g., a
method is invoked)

A template definition can refer to a class


template or its instances but a n non-template
can only refer to template instances.
Jan-Feb 2016

202

Friend & Static Declaration


There are 3 kinds of friend declarations
Non-template friend.
A bound friend class template.

One-to-one mapping between the instance of a class template


and its friend

An unbound friend class template.

One-to-many mapping between the instance of a class


template and its friend

Operators can be overloaded for a class template

A static data member in a class template is


itself a template.
Each static data member instantiation
corresponds to a class template instantiation.
Jan-Feb 2016

203

Source code organization


Inclusion Model

Make the template definition visible to


compiler at the point of instantiation

Include source files as well.

Increase in build and link time

Instantiate the types you need explicitly in a


separate compile unit.

Cannot use benefits of lazy instantiation.

Separation Model
Use keyword export in front of definition.

Jan-Feb 2016

Not many compiler supports the feature.


204

Template specialization
Allows to make specific implementation when
pattern is of determined type.
The syntax is
template<> class XXX<Type> {..}

No member is inherited from the generic


template to specialized one. So, must define
ALL members equating them to specialization
Class templates can be partially specialized
too.
A totally disjoint template that the compiler gives a
priority while instantiation.
Jan-Feb 2016

205

Templates & Derivation


A template expresses a commonality across
types
Two types generated from a common template are
different.

A Base class expresses commonality of


representation and calling interface.
Example
template <class T, class A> class specalContainer :
public Container<T>, A;
specialContainer<Node, Fast_Allocator> s;
specialContainer<Node, Shared> s1;
specialContainer<ProcessDescriptor, Fast_Allocator>
p;
Jan-Feb 2016
206

Template Inheritance: A Base


Template
template<class T>
class set {
public :
Set ( ) { } ;
virtual void add (const T
&val);
int length ( ) ;
int find (const T &val);
private:
List<T> items;
};

Jan-Feb 2016

template<class T>
void Set<T> : : add (const T &val)
{
if (items.find (val) ) return;
items.put (val) ;
}
template<class T>
int Set<T> : : length ( )
{
return items.length ( ) ;
}
template<class T>
int Set<T> ::find (const T &val)
{
return (int) items.find(val);
}

207

Template Inheritance: A
Derived Template
/* boundset.h */
#include set.h
template<class T>
class BoundSet : public Set<T>
public:
BoundSet (const T &lower,
const T &upper);
void add(const T &val);
private:
T min;
T max;
};

Jan-Feb 2016

template<class T>
BoundSet<T>:: BoundSet (const T
&lower, const T &upper)
: min (lower), max (upper)
{
}
template<class T>
void BoundSet<T> : :add(const T
&val)
{
if (find (val) ) return;
if ( (val <= max) && (val
>= min) )
Set<T>: : add
(val) ;
}
208

Using a Derived Template Class


int main ( ) {
register int i ;
BoundSet<int> bsi (3, 21);
Set<int> *Setptr = &bsi;
for (i = 0; i < 25; i++)
setptr->add( i ) ;
if (bsi.find (4)
cout << We found an expected value\n;
if (bsi.find (0) || bsi.find(25 ) ) {
cout << We found an Unexpected value\n;
return 23;
}
else
cout << We found NO unexpected value\n;
return 0;
}

Jan-Feb 2016

209

Inheritance vs Templates
Inheritance : helps in reusing object code
Templates : helps in reusing source-code
object code size of template code is therefore much
less.

Compiler view
Constructor of objects containing virtual functions
must initialize the vptr table.
Template class knows the type of the class at
compile-time instead of having to determine it at
run-time (as in case of virtual function usage)

Jan-Feb 2016

210

Inheritance vs Templates:
Example
Implement the following command.
# ECHO infile outfile
main() {
(argc > 2 ? ofstream (argv[2]
,ios::out) : cout) <<
(argc > 1 ? ifstream (argv[1],
ios::in) : cin)
.rdbuf();
}

main()
{
fstream in, out;
if (argc > 1) in.open(argv[1],
ios::in);
if (argc > 2) out.open(argv[2],
ios::out);
Process(in.is_open() ? in
: cin,
out.is_open() ? out :
cout);
}

How to implement Process ?


Two ways to get the
polymorphic behavior
virtual function and templates

Jan-Feb 2016

211

Inheritance vs Templates:
Solution
template<typename In, typename
out>
void process(In& in, Out& out)
{
// out << in.rdbuf();
}

Merely requires that


the passed objects
to have suitable
interface (such as
member function
named rdbuf(). )
Jan-Feb 2016

void Process (basic_istream& in,


basic_ostream& out) {
// out << in.rdbuf();
}

Requirement:

cin and ifstream both derived


from basic_istream
The common base class
basic_istream has suitable
interface rdbuf.

Both Methods solve the current


problem.
But templates provide
extensibility.

Other streams can be provided


with rdbuf() interface.
Other streams cannot be
guaranteed to be derived from
the same base class
212

Another Example
A collection of classes is required for
Stack: for ints , strings, floats etc.

Has operations: push, pop, length of stack.

transportationMode . For airplane, car, boat etc.

Has features : move, comfort etc


each move in diff ways.
Each provide different level of comfort.

Analyze if the type being manipulated has any


affect on the behavior of class .
If type does not affect the behavior, use templates
If type affects the behavior, use virtual functions
(inheritance)
Jan-Feb 2016

213

Thank You

Ranking of Programming Languages in Dec 2014


TIOBE Index for December 2014
Programming
Dec-14Dec-13Change Language
Ratings Change
1
2
3
4
5
6
7
8
9
10
1112
13
14
15
16
1718
19
20

1
2
3
4
5
6
10
8
11
12
38
9
17
18
15
13
20
14

=
=
=
=
=
=
+
=
+
+
+
+

+
+

C
Java
Objective-C
C++
C#
PHP
JavaScript
Python
Visual Basic .NET
Perl
Visual Basic
R
Transact-SQL
PL/SQL
Pascal
Delphi/Object Pascal
Swift
Ruby
F#
MATLAB

17.59%
14.96%
9.13%
6.10%
4.33%
2.75%
2.43%
2.29%
2.24%
1.83%
1.80%
1.63%
1.47%
1.33%
1.17%
1.12%
1.07%
0.98%
0.89%
0.87%

-0.30%
-2.35%
-1.07%
-2.16%
-1.29%
-2.53%
0.58%
0.08%
0.55%
0.75%
1.80%
1.38%
-0.40%
0.73%
0.58%
0.43%
1.06%
0.05%
0.32%
0.16%

http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html
Jan-Feb 2016

215

Ranking of Programming Languages in Jan 2014


TIOBE Index for January 2014
Jan-14 Jan-13Change Programming Language

Ratings Change

1
1
=
C
17.87% 0.02%
2
2
=
Java
16.50% -0.92%
3
3
=
Objective-C
11.10% 0.82%
4
4
=
C++
7.55% -1.59%
5
5
=
C#
5.86% -0.34%
6
6
=
PHP
4.63% -0.92%
7
7
=
(Visual) Basic
2.99% -1.76%
8
8
=
Python
2.40% -1.77%
9
10
+
JavaScript
1.57% -0.41%
10
22
+
Transact-SQL
1.56% 0.98%
11
12
+
Visual Basic .NET
1.56% 0.52%
12
11

Ruby
1.08% -0.69%
13
9

Perl
0.92% -1.35%
14
14
=
Pascal
0.78% -0.15%
15
17
+
MATLAB
0.78% 0.14%
16
45
+
F#
0.72% 0.53%
17
21
+
PL/SQL
0.63% 0.05%
18
35
+
D
0.63% 0.33%
19
13

Lisp
0.60% -0.35%
20
15

Delphi/Object Pascal
0.60% -0.32%
http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html
Jan-Feb 2016

216

Jan-Feb 2016

217

You might also like