This document discusses object-oriented programming in C++. It covers several topics related to OOP in C++ including classes, constructors, destructors, inheritance, polymorphism, and templates. The document consists of lecture slides that define key concepts and provide examples to illustrate how various OOP features work in C++.
5. TOPICS
Const-ness
Reference Data Type
Inline Functions
Default Function Parameters
Function Overloading & Resolution
Dynamic Memory Allocation
5OOP in C++Jan 2014
6. 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 can not 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;
6OOP in C++Jan 2014
7. 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;
7OOP in C++Jan 2014
8. 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
8OOP in C++Jan 2014
9. 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.
9OOP in C++Jan 2014
10. 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
10OOP in C++Jan 2014
11. 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;
}
11OOP in C++Jan 2014
12. 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.
12OOP in C++Jan 2014
13. 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
13OOP in C++Jan 2014
14. Inline Functions
Inline functions act like functions
They can be class members
Type checking is performed
They can be overloaded
They 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
14OOP in C++Jan 2014
15. 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.
15OOP in C++Jan 2014
16. 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.
16OOP in C++Jan 2014
17. Default Arguments: Example
Following are some examples of
functions with default arguments.
Void ff (int, float = 0.0, char *); // Error
Void ff2(int, float = 0, char *=NULL); // OK
Void ff2(int float = 1, char *= NULL); // 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
17OOP in C++Jan 2014
18. 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 re-
declare”.
Overloading allows static polymorphism
18OOP in C++Jan 2014
19. 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)
Exact Match
Promotion
Standard type conversion
User defined type conversion
19OOP in C++Jan 2014
20. 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
20OOP in C++Jan 2014
21. 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: int (*fp) (int);
void f(int x, fp); int g(int);
Call: f(5, g)
Qualification conversion
Converting pointer (only) to const pointer.
21OOP in C++Jan 2014
22. 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
22OOP in C++Jan 2014
23. Examples of Resolution
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?
}
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?
}
3. Conversion Sequence
int arr[3];
void putValues(const int *);
int main() {
putValues(arr);
}
23OOP in C++Jan 2014
24. new/delete operators
In C++, the new and delete operators provide built-in
language support for dynamic memory allocation and de-
allocation.
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!
24OOP in C++Jan 2014
25. 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.
25OOP in C++Jan 2014
27. TOPICS
Class Members
Constructor & Destructor
Friends
Static Members
Struct & Union
27OOP in C++Jan 2014
28. 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.
28OOP in C++Jan 2014
29. Class
A Class is defined by “class” keyword.
Each member in a class has an access specifier.
private – these members are accessible inside the definition
of the class.
public – these members are 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.
29OOP in C++Jan 2014
30. 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;
};
int main ()
{
Employee e1; Employee *e2;
e2 = new Employee;
e1.setName(“Amit”); e2->name =
strdup(“Ashis"); // Error
e2.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); }
Jan 2014 OOP in C++ 30
31. More on this
Type of this
X * const
Necessity of this to the programmer
Distinguishing data member from non-member
variable
Explicit Use
class DoublyLinkedNode DoublyLinkedNode::append(DoublyLinkedNode *x)
{ {
DoublyLinkedNode *prev, *next; next = x;
int data; x->prev = this;
public: }
void append(DoublyLinkedNode *x);
}
31OOP in C++Jan 2014
32. 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
32OOP in C++Jan 2014
33. 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.
33OOP in C++Jan 2014
34. 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();
34OOP in C++Jan 2014
35. 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.
35OOP in C++Jan 2014
36. 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.
36OOP in C++Jan 2014
37. 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.
37OOP in C++Jan 2014
38. 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;
}
38OOP in C++Jan 2014
39. Class String::Constructor &
Destructor
String::String() {
data = NULL;
len = 0;
}
String::String(const char *s) {
data = new char[strlen(s)+1];
len = strlen(s);
strcpy(data, s);
}
void ~String() {
if (data != NULL)
delete [] data;
}
int main()
{
String s1; //default constructor
String s11(); //Error
String s1(“test”);
char str[6];
strcpy(str, “Hello”);
String s2(str);
String s3(s2); //Copy Constructor
String s4 = new String(“one”);
String s5 = new String();
delete s4;
delete s5;
}
39OOP in C++Jan 2014
40. 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”) };
40OOP in C++Jan 2014
41. 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.
A String Object
data
len
H e l l o n
41OOP in C++Jan 2014
42. 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.
42OOP in C++Jan 2014
43. 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 constructor’s 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
43OOP in C++Jan 2014
44. 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.
44OOP in C++Jan 2014
45. 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
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
}
45OOP in C++Jan 2014
46. 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
46OOP in C++Jan 2014
48. 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;
};
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];
}
}
48OOP in C++Jan 2014
49. 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.
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;
} ;
49OOP in C++Jan 2014
50. 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
class X {
public:
static int count; // This is a
declaration
X() { count++; }
}
X::count = 0; //Definition & Initialization
int main()
{
X a, b, c;
printf(“%d %d %d %dn”, X::count, a.count,
b.count, c.count);
}
The output will be 3 3 3 3
50OOP in C++Jan 2014
51. Static Data: A List
class ListNode {
public:
static ListNode *first;
private:
ListNode *next;
int data;
public:
ListNode(int x);
print();
}
List Node *ListNode::first = NULL;
ListNode::ListNode(int x) {
data = x;
next = NULL;
if (first == NULL)
first = this;
else
{
next = first;
first = this;
}
}
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
51OOP in C++Jan 2014
52. 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.
52OOP in C++Jan 2014
53. 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;
}
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 non-
inline function is called.
53OOP in C++Jan 2014
55. 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.
55OOP in C++Jan 2014
56. 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.
56OOP in C++Jan 2014
57. 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;
} ;
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);
}
57OOP in C++Jan 2014
58. Overloading Assignment
Operator
String & String: :operator=( char *rhs)
{
data = new char [strlen(rhs) + 1];
strcpy ( data, rhs);
return *this ;
}
Bug:
Memory Leak as previous
data of this is not
deleted.
.
.
.
String String: :operator=( String &rhs)
{
data = new char [rhs.len + 1];
strcpy ( data, rhs.data);
return *this ;
}
Bug:
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 &
58OOP in C++Jan 2014
59. Overloading Assignment
Operator
String & String: :operator (String &rhs)
{
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) .
59OOP in C++Jan 2014
60. 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.
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;
60OOP in C++Jan 2014
61. 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.
61OOP in C++Jan 2014
62. 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:
void operator ++ (int a);
62OOP in C++Jan 2014
63. 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.
63OOP in C++Jan 2014
64. 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.
64OOP in C++Jan 2014
65. 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 2014 OOP in C++ 65
66. Overloading using const
Class String {
public:
char & operator [ ] (int pos)
{ return data[pos]; }
const char & operator [ ] (int pos)
{ return data[pos]; }
private:
char * data;
……
}
String s1 = “Hello”;
cout << s[0]; // fine
s[0] = ‘x’; // fine
const String cs = “World”;
cout << s[0]; // fine
s[0] = ‘x’; // Error!!!
Jan 2014 OOP in C++ 66
67. 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 2014 OOP in C++ 67
70. 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 2014 70OOP in C++
71. 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 2014 71OOP in C++
72. 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 2014 72OOP in C++
73. Assume the following
class hierarchy
class C: public B
{ .. };
class B: public A
{ .. };
class A
{ .. };
Object Layout in Inheritance
Layout for an object
of type C
A-Part Data Member
B-Part Data Member
C-Part Data Member
Jan 2014 73OOP in C++
74. 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 2014 74OOP in C++
75. 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 2014 75OOP in C++
76. 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 2014 76OOP in C++
77. Example of Derived Class
Constructor
Employee::Employee(long id)
{
this->id = id;
}
Manager::Manager(long id, int n) : Employee(id)
{
numberOfPeopleManaged = n;
}
Jan 2014 77OOP in C++
78. 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 2014 78OOP in C++
79. 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 2014 79OOP in C++
80. 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 2014 80OOP in C++
81. 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 2014 81OOP in C++
82. 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 2014 82OOP in C++
83. 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 re-
defined in the derived class then the
latter definition hides the former one.
Jan 2014 83OOP in C++
84. 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;
X *b = &a;
i = b->f(); j = a.f();
k = b->g(); m = a.g();
printf(“%d %d %d %dn”, i, j, k, m);
}
Jan 2014 84OOP in C++
Output will be 2 4 6 6
85. 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 2014 85OOP in C++
86. 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.
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
Jan 2014 86OOP in C++
87. 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 2014 87OOP in C++
88. 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 2014 88OOP in C++
89. 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 2014 89OOP in C++
90. Polymorphic Array: Class
Definitions
class Shape {
public:
virtual double calculateArea() =
0;
};
class triangle : public Shape() {
private:
Point a, b, c;
Triangle(double x_a, double y_a,
double x_b, double y_b,
double x_c, double y_c);
public:
double calculateArea();
};
class Circle : public Shape() {
private:
Point centre;
double radius;
Circle(double x_centre,
double y_centre,
double r);,
public:
double calculateArea();
};
Jan 2014 90OOP in C++
91. Polymorphic Array: main
function
int main() {
Shape *pArr = NULL;
int n = getInput(pArr);
for (int i = 0; i < n; i++) {
double area =
Shape[i]->calculateArea();
printf (“%d %lf n”, i, area);
}
}
int getInput(Shape *pArr) {
printf(“Which Shape do you want to
create?n”);
printf(“Write 1 for triangle, 2 for
rectangle, 3 for circle and 0 to
quitn”);
int i,
double x_a, x_b, x_c, y_a, y_b, y_c;
while (1) { int j = 0;
scanf(“%d”, &i);
switch (i) {
case 0: break;
case 1:
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,
&y_a, &x_b, &y_b, &x_c, &y_c);
break;
……..
}
}
}
Jan 2014 91OOP in C++
92. Inheritance: Benefits
Code Sharing/Reuse
Consistency of Interface
Construction of Software Components
Rapid Prototyping
Information Hiding
Jan 2014 92OOP in C++
93. Inheritance: Cost
Execution Speed
Program Size
Message Passing Overhead
Program Complexity
Jan 2014 93OOP in C++
94. 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 2014 94OOP in C++
95. 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 2014 95OOP in C++
96. 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 2014 96OOP in C++
97. 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 2014 97OOP in C++
98. 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 2014 98OOP in C++
99. 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 2014 99OOP in C++
100. 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 2014 100OOP in C++
101. 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 2014 101OOP in C++
102. 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 2014 102OOP in C++
103. 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 2014 103OOP in C++
104. 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 2014 104OOP in C++
106. 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 2014 OOP in C++ 106
107. 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;
}
107OOP in C++Jan 2014
108. 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 2014 OOP in C++ 108
109. 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”;
109OOP in C++Jan 2014
110. 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”;
110OOP in C++Jan 2014
111. 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
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;
}
111OOP in C++Jan 2014
112. Ambiguity: Example
class B;
class A {
public:
A (const B &);
...
};
class B {
public:
operator A () const;
};
void f(const A &);
B b;
f(b); //Error - Ambiguous
Which one to use for
casting?
Constructor in A OR
Cast Operator in B
112OOP in C++Jan 2014
113. 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 *()” .
113OOP in C++Jan 2014
114. 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]
};
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 ;
}
114OOP in C++Jan 2014
115. 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];
};
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;
}
115OOP in C++Jan 2014
116. 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
116OOP in C++Jan 2014
117. 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
117OOP in C++Jan 2014
118. 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 2014 OOP in C++ 118
119. 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 2014 OOP in C++ 119
120. 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;
}
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.
Jan 2014 120OOP in C++
121. 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 2014 121OOP in C++
122. 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 2014 OOP in C++ 122
123. 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 2014 OOP in C++ 123
124. 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 2014 OOP in C++ 124
125. 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
...
}.
static_cast: Example
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 run-
time type check is made
to ensure the safety of
the conversion.For such
conversions dynamic_cast
should be used.
Jan 2014 125OOP in C++
126. 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;
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.
Jan 2014 OOP in C++ 126
127. 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 2014 127OOP in C++
128. 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 2014 OOP in C++ 128
129. 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;
}
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.
Jan 2014 129OOP in C++
130. 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 2014 OOP in C++ 130
131. 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 doesn’t work!
... // do SpecialWindow-
} // specific stuff
...
};
Jan 2014 OOP in C++ 131
132. 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 2014 OOP in C++ 132
133. type_info class
Features of type_info class (contd):
The “name” member function returns a const char*
to a null-terminated string representing the human-
readable 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 2014 OOP in C++ 133
134. 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
134OOP in C++Jan 2014
135. typeid operator
When the operand of typeid is of a non-
polymorphic 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.
135OOP in C++Jan 2014
136. The expression usually
points to a polymorphic
type (a class with virtual
functions).
The pointer must be de-
referenced 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
#include <iostream>
#include <typeinfo.h>
class Base {
public: virtual void vvfunc()
{} }
class Derived : public Base {};
typeid: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;
}
136OOP in C++Jan 2014
137. dynamic_cast operator
Syntax:
dynamic_cast<type-
id> (expression)
The expression
dynamic_cast<type-
id>( expression)
converts the operand
expression to an
object of type type-
id.
It is used for down-
casting.
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
...
}
137OOP in C++Jan 2014
138. 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
...
}
138OOP in C++Jan 2014
139. 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.
139OOP in C++Jan 2014
140. 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 non-
polymorphic 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.
140OOP in C++Jan 2014
141. 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.
141OOP in C++Jan 2014
143. Topics
Basic Concept of Exceptions
try-catch block in C++
Semantics of throw
Jan 2014 143OOP in C++
144. 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 2014 144OOP in C++
145. 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 2014 145OOP in C++
146. C-Style Error Handling
int
Calculator::divide (int i)
{
if (i == 0)
{
// what do we do?
}
else
{
value /= i;
}
return value;
}
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
Jan 2014 146OOP in C++
147. “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 2014 147OOP in C++
148. 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 2014 148OOP in C++
149. Example of Exception Handling
in C++
class DivideByZero {
private:
int dividend;
public:
print() {
cout << dividend << “is divided by zero”
<<endl;
}
DivideByZero(int d) { dividend = d; }
};
int Calculator::divide(int i) throws DivideByZero
{
if (i ==0)
throw DivideByZero(value);
value /= i;
return value;
}
int main (int argc, char **argv) {
int i = 0;
Calculator c;
try {
c.divide (0);
cout << c.getValue ();
}
catch (DivideByZero& ext) {
ex.print();
return 1;
}
return 0;
}
Jan 2014 149OOP in C++
150. 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 2014 150OOP in C++
151. 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 2014 151OOP in C++
152. 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
(int i) throw (int);
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
Jan 2014 152OOP in C++
153. Stack Frame
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
Pushed on program call stack at run-
time. 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
previous frame pointer
return address
parameters
automatic variables
Jan 2014 153OOP in C++
154. Illustrating the Call Stack
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;
}
Stack frame for function main
Pushed on program call stack
With stack variables i and c
With parameters argc and argv
Note that parameters are
initialized at frame creation
Variables are not necessarily
initialized at frame creation
May occur later in called
function
argc argv
i c value_
main
Jan 2014 154OOP in C++
155. 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;
}
Enter function main
Stack variable initialized to
0
argc argv
i c value_
main
Jan 2014 155OOP in C++
156. 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;
}
Call Default Constructor for c
Push 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
argc argv
i c value_
main
Calculator::
Calculator( ) this
Jan 2014 156OOP in C++
157. 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_;
}
Enter function Calculator::Calculator ( )
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
argc argv
i c value_
main
Calculator::
Calculator() this
Jan 2014 157OOP in C++
158. 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_;
}
Return from function
Calculator::Calculator ( )
Pop the stack frame, return to
previous
argc argv
i c value_main
Jan 2014 158OOP in C++
159. 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;
}
Call divide method on c
Push a new stack frame
Contains parameters this and i
Copy address of current instance into
this
Copy value 0 into i
void Calculator::
divide (int )
main
argc argv
i c value_
this i
Jan 2014 159OOP in C++
160. Illustrating the Call Stack, cont.
Enter function Calculator::divide
(int)
Test i equal to 0 and take the true
branch
Throw integer i
main
void Calculator::
Calculator (int )
argc argv
i c value_
this i
Calculator::Calculator ()
: value_ (0)
{
}
void
Calculator::divide (int i) throw (int)
{
if (i == 0) {
throw i;
} else {
value_ /= i;
}
cout << value_;
}
Jan 2014 160OOP in C++
161. 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_;
}
Thrown exception unwinds call stack
Notice control skips over cout statement
to end
Pop the stack frame, return to previous
Return from function void
Calculator::divide ( )
argc argv
i c value_
main
Jan 2014 161OOP in C++
162. 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;
}
We’ve reached an enclosing
try/catch scope
So stack unwinding stops
Control jumps to first matching
catch block
Again, skips over intervening cout
statement
argc argv
i c value_
main
Jan 2014 162OOP in C++
163. More on catch
try {
// can throw an exception
}
catch (Derived &d) {
// ...
}
catch (Base &b) {
// ...
}
catch (...) // catch all...
{
// ...
}
Control jumps to first
matching catch block
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
Jan 2014 163OOP in C++
164. A Few More on catch
try
{
// can throw an exception
}
catch (MyClass &e)
{
// ...
throw; // rethrows e
}
catch (int)
{
// ...
}
catch (...) // catch all...
{
// ...
}
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
Jan 2014 164OOP in C++
166. 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 2014 166OOP in C++
167. template<class X> void swap (X &one, X
&other)
{
X temp;
temp = one;
one = other;
other = temp;
}
Main() {
int I=10, j=20;
swap(I, j);
String s1(“abc”), s2(“def”);
swap(s1, s2);
}
Function Template: An Example
void swap(int &i, int &j)
{
int temp;
temp = i;
i = j;
j = temp;
}
void swap(String &i, String &j)
{
String temp;
temp = i;
i = j;
j = temp;
}
Type parameter
Type parameter list
Template instantiation
Jan 2014 167OOP in C++
168. 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 class, (i.e. type), parameters
Jan 2014 168OOP in C++
169. 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 2014 169OOP in C++
170. 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 2014 170OOP in C++
171. 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 2014 171OOP in C++
172. 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 2014 172OOP in C++
173. 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 2014 173OOP in C++
174. 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 2014 174OOP in C++
175. 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;
};
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;
}
Jan 2014 175OOP in C++
176. 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 () << “ itemsn” ;
return 0;
}
Jan 2014 176OOP in C++
177. 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 2014 177OOP in C++
178. 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 2014 178OOP in C++
179. 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 2014 179OOP in C++
180. 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 2014 180OOP in C++
181. 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 2014 181OOP in C++
182. 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.
Not many compiler supports the feature.
Jan 2014 182OOP in C++
183. 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 2014 183OOP in C++
184. 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 2014 184OOP in C++
185. 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;
};
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);
}
Jan 2014 185OOP in C++
186. 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;
};
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) ;
}
Jan 2014 186OOP in C++
187. 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 valuen”;
if (bsi.find (0) || bsi.find(25 ) ) {
cout << “We found an Unexpected valuen”;
return 23;
}
else
cout << “We found NO unexpected valuen”;
return 0;
}
Jan 2014 187OOP in C++
188. 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 2014 188OOP in C++
189. 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 2014 189OOP in C++
190. 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(). )
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
Jan 2014 190OOP in C++
191. 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 2014 191OOP in C++