Vous êtes sur la page 1sur 192

Object-Oriented Programming in C++ CS20006: Software Engineering

Lecture 02Prof. Partha Pratim Das

Jan 2013

Object-Oriented Modeling & Programming

PROGRAMMING IN C++
Jan 2013 OOP in C++ 2

Topics
Procedural Enhancements in C++ over C Classes Overloading Inheritance Type Casting Exceptions Templates
Jan 2013 OOP in C++ 3

Object Oriented Programming in C++

PROCEDURAL ENHANCEMENTS IN C++


Jan 2013 OOP in C++ 4

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

Jan 2013

OOP in C++

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;
Jan 2013 OOP in C++ 6

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 2013

OOP in C++

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 2013

OOP in C++

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 2013 OOP in C++ 9

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 2013

OOP in C++

10

Returning a Reference
#include <iostream.h.> 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 2013 OOP in C++ 11

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 2013

OOP in C++

12

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 2013

OOP in C++

13

Inline Functions
Inline functions act like functions


Jan 2013

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
OOP in C++ 14

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 2013 OOP in C++ 15

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 2013 OOP in C++ 16

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); ff(int, float, char = a); // Error // OK // Error Redefinition

Assume that ff.h contains the following declaration

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 2013 OOP in C++ 17

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 2013

OOP in C++

18

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 2013

Exact Match Promotion Standard type conversion User defined type conversion
OOP in C++ 19

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 2013 OOP in C++ 20

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.
Jan 2013 OOP in C++ 21

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 2013

OOP in C++

22

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?

3. Conversion Sequence
int arr[3]; void putValues(const int *); int main() { putValues(arr); }

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); }
Jan 2013

//Which set?
OOP in C++ 23

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 2013 OOP in C++ 24

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 2013 OOP in C++ 25

Object Oriented Programming in C++

CLASS
Jan 2013 OOP in C++ 26

TOPICS
Class Members Constructor & Destructor Friends Static Members Struct & Union

Jan 2013

OOP in C++

27

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 2013

OOP in C++

28

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.

Jan 2013

OOP in C++

29

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); }
OOP in C++ 30

Jan 2013

More on this
Type of this
Necessity of this to the programmer
X * const Distinguishing data member from non-member variable Explicit Use
class DoublyLinkedNode { DoublyLinkedNode *prev, *next; int data; public: void append(DoublyLinkedNode *x); } DoublyLinkedNode::append(DoublyLinkedNode *x) { next = x; x->prev = this; }

Jan 2013

OOP in C++

31

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 2013

OOP in C++

32

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 2013 OOP in C++ 33

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 2013

OOP in C++

34

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

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 2013 OOP in C++ 35

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 2013

OOP in C++

36

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 2013

OOP in C++

37

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 2013 OOP in C++ 38

Class String::Constructor & Destructor


String::String() { int main() { String s1; //default constructor String s11(); //Error String s1(test); String::String(const char *s) { data = new char[strlen(s)+1]; len = strlen(s); strcpy(data, s); } void ~String() { if (data != NULL) delete [] data; }
Jan 2013

data = NULL;
len = 0; }

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; }
OOP in C++ 39

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.

Jan 2013

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


OOP in C++ 40

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

Jan 2013

OOP in C++

41

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 2013

OOP in C++

42

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 2013

OOP in C++

43

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 2013 OOP in C++ 44

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 }

Jan 2013

OOP in C++

45

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 2013 OOP in C++ 46

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; } 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; }

Jan 2013

OOP in C++

47

Friends of More Than One class


class Matrix; // Forward declaration to make // declaration of crossprod legal class Vector { public : void Vector(int n) ; friend Vector prod(Matrix *pM, Vector *pV); int elements[10] ; int n; }; class Matrix { public : void 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]; } }

Jan 2013

OOP in C++

48

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; } ;

Jan 2013

OOP in C++

49

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 %d\n, X::count, a.count, b.count, c.count); }

The output will be 3 3 3 3

Jan 2013

OOP in C++

50

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; } } Jan 2013 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


OOP in C++ 51

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 2013 OOP in C++ 52

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 noninline function is called.
OOP in C++ 53

Jan 2013

Object Oriented Programming in C++

OPERATOR OVERLOADING
Jan 2013 OOP in C++ 54

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 2013

OOP in C++

55

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 2013 OOP in C++ 56

Example of overloading operator +


/ * string .h * / const int max_string_length = 128 ; class String { public : String opertator + (char *text) ; String opertator + (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); }

Jan 2013

OOP in C++

57

Overloading Assignment Operator


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

Bug: Memory Leak as previous data of this is not deleted.


. . .

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 &


OOP in C++ 58

Jan 2013

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) .
Jan 2013 OOP in C++ 59

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; } Integer & operator*(Integer &lhs, Integer &rhs) { Integer *result = new Integer( lhs.data * rhd.data); return *result; }

Problem: Returning reference to a local object. The code fails.


Jan 2013

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

OOP in C++

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 2013 OOP in C++ 61

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);

Jan 2013

OOP in C++

62

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 2013

OOP in C++

63

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 2013 OOP in C++ 64

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 2013 OOP in C++ 65

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 2013

OOP in C++

66

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 2013 OOP in C++ 67

Object-Oriented Programming in C++

INHERITANCE
Jan 2013 OOP in C++ 68

Topics
Fundamentals of Inheritance protected Access Specifier Initialization

Virtual Functions

Jan 2013

OOP in C++

69

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 2013

OOP in C++

70

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 2013 OOP in C++ 71

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 2013 OOP in C++ 72

Object Layout in Inheritance


Assume the following class hierarchy class C: public B { .. }; class B: public A { .. }; class A { .. };
Jan 2013

Layout for an object of type C

A-Part Data Member B-Part Data Member C-Part Data Member

OOP in C++

73

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 2013 OOP in C++ 74

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 2013 OOP in C++ 75

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 2013

OOP in C++

76

Example of Derived Class Constructor


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

Jan 2013

OOP in C++

77

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 2013 OOP in C++ 78

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 2013

OOP in C++

79

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 2013

OOP in C++

80

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 2013

OOP in C++

81

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 2013

OOP in C++

82

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 2013 OOP in C++ 83

Virtual Function: Example


class X{ class Y: public X{

public:
int f(){ return 2; } virtual int g(){ return 3;} }; main() { Y a; int i, j , k, m; X *b = &a; i = b->f(); j = a.f(); k = b->g(); m = a.g();

public:
int f(){ return 4;} int g(){ return 6;} };

Output will be 2 4 6 6

printf(%d %d %d %d\n, i, j, k, m); }


Jan 2013 OOP in C++ 84

Redefining a Non-Virtual Function


Simply do not do that.
class X() {
protected: 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 2013 OOP in C++ 85

class Y : public X {
protected: void f(); };

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 2013

OOP in C++

86

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 2013 OOP in C++ 87

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 2013 OOP in C++ 88

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 2013

OOP in C++

89

Polymorphic Array: Class Definitions


class Shape { class Circle : public Shape() {

public:
0; }; class triangle : public Shape() { virtual double calculateArea() =

private:
Point centre; double radius; Circle(double x_centre, double y_centre, double r);, public: double calculateArea(); };

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(); };
Jan 2013 OOP in C++

90

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); 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 2013 OOP in C++ 91

printf(Write 1 for triangle, 2 for rectangle, 3 for circle and 0 to quit\n);

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

Jan 2013

OOP in C++

92

Inheritance: Cost
Execution Speed Program Size Message Passing Overhead Program Complexity

Jan 2013

OOP in C++

93

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 2013 OOP in C++ 94

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) {
b[0].f(); b[1].f(); } }

int main() {
Derived d[10]; f(d);

Derived is publicly derived from Base. Class Base has a virtual function f which is redefined in Derived.
Jan 2013 OOP in C++ 95

Default Parameter & Virtual Function


Do not change the default parameter in a redefined virtual function
class X() { protected: virtual void f(int i = 10); }; 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 2013 OOP in C++ 96

class Y : public X { protected: virtual void f(int i =20); };

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 2013 OOP in C++ 97

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 2013 OOP in C++ 98

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 2013 OOP in C++ 99

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 2013

OOP in C++

100

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 2013

OOP in C++

101

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 2013

OOP in C++

102

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 2013 OOP in C++ 103

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 2013 OOP in C++ 104

Object-Oriented Programming in C++

TYPE CASTING
Jan 2013 OOP in C++ 105

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 2013 OOP in C++ 106

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 2013 OOP in C++ 107

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 2013 OOP in C++ 108

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 2013 OOP in C++ 109

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 2013 OOP in C++ 110

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; }

Jan 2013

OOP in C++

111

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

Jan 2013

OOP in C++

112

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 2013

OOP in C++

113

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 2013

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 ; }
114

OOP in C++

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; }
115

Jan 2013

OOP in C++

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 2013 OOP in C++ 116

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 2013

OOP in C++

117

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 2013

OOP in C++

118

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 2013

OOP in C++

119

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 2013

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.
120

OOP in C++

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 2013 OOP in C++ 121

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 2013

OOP in C++

122

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 2013

OOP in C++

123

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 2013

OOP in C++

124

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 ... }.

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.

Jan 2013

OOP in C++

125

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 2013

OOP in C++

126

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 2013 OOP in C++ 127

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 2013

OOP in C++

128

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 2013

OOP in C++

129

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; Dd1; 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 2013

OOP in C++

130

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 2013

OOP in C++

131

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 2013

OOP in C++

132

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 2013

OOP in C++

133

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 2013 OOP in C++ 134

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 2013

OOP in C++

135

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
#include <iostream> #include <typeinfo.h> class Base { public: virtual void vvfunc() {} } class Derived : public Base {};
Jan 2013 OOP in C++ 136

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; }

dynamic_cast operator
Syntax:
dynamic_cast<typeid> (expression)
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 ... }

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

OOP in C++

137

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 2013

OOP in C++

138

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 2013

OOP in C++

139

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 2013

OOP in C++

140

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 2013 OOP in C++ 141

Object Oriented Programming in C++

EXCEPTIONS
Jan 2013 OOP in C++ 142

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

Jan 2013

OOP in C++

143

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 2013 OOP in C++ 144

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 2013 OOP in C++ 145

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 2013

OOP in C++

146

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 2013

OOP in C++

147

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 2013 OOP in C++ 148

Example of Exception Handling in C++


class DivideByZero { private: int dividend; public: print() { cout << dividend << is divided by zero <<endl; } catch (DivideByZero& ext) { ex.print(); return 1; } return 0; } int main (int argc, char **argv) { int i = 0; Calculator c; try { c.divide (0); cout << c.getValue ();

}
DivideByZero(int d) { dividend = d; } }; int Calculator::divide(int i) throws DivideByZero { if (i ==0) throw DivideByZero(value); value /= i; return value; } Jan 2013

OOP in C++

149

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 2013

OOP in C++

150

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 2013

OOP in C++

151

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);
Jan 2013

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 Promises nothing will be thrown Comma separated
152

A throw clause with no types Can list multiple types

OOP in C++

Stack Frame
automatic variables parameters

previous frame pointer


return address

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 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
153

Jan 2013

OOP in C++

Illustrating the Call Stack


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

Stack frame for function main


Pushed on program call stack With stack variables i and c With parameters argc and argv

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

Note that parameters are initialized at frame creation Variables are not necessarily initialized at frame creation
May occur later in called function

i main

value_ argv
154

argc
OOP in C++

Jan 2013

Illustrating the Call Stack, cont.


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

Enter function main


Stack variable initialized to 0

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

i main

value_ argv
155

argc
OOP in C++

Jan 2013

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; }

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

Calculator:: Calculator( ) i main

this c value_ argv


156

return 0;
}

argc
OOP in C++

Jan 2013

Illustrating the Call Stack, cont.


Calculator::Calculator () : value_ (0) {} void Calculator::divide (int i) throw (int)

Enter function Calculator::Calculator ( )


Member variable value_ of stack variable c is initialized to zero
There may be multiple Calculator instances Answer: implicit this parameter in stack frame

How do we know which value_ to set?


{
if (i == 0) { throw i; } else { value_ /= i; } cout << value_; }
Jan 2013 OOP in C++

Calculator:: Calculator()

this

i
main

value_
argv
157

argc

Illustrating the Call Stack, cont.


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

Return from function Calculator::Calculator ( ) Pop the stack frame, return to previous

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


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

value_ /= i;
} cout << value_; }
Jan 2013

main

value_
argv
158

argc
OOP in C++

Illustrating the Call Stack, cont.


int main (int argc, char **argv) { int i = 0; Calculator c; try { c.divide (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
this i main argc argv
159

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

void Calculator:: divide (int )

i value_

OOP in C++

Illustrating the Call Stack, cont.


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

Enter function Calculator::divide (int)


Test i equal to 0 and take the true branch Throw integer i

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

void Calculator:: Calculator (int ) i main

this c

i value_ argv
160

argc
Jan 2013 OOP in C++

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 ( )

i main

value_ argv
161

argc
OOP in C++

Jan 2013

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

i main

value_ argv
162

argc
Jan 2013 OOP in C++

More on catch
try { // can throw an exception } catch (Derived &d) { // ... }

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
163

catch (Base &b) {


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

OOP in C++

Jan 2013

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 Avoids class-slicing problem if catch as base type, rethrow Preserves polymorphism More on this in later lectures

More correct

Can leave off variable name


Unless catch block needs to do something with the instance that was caught
164

Jan 2013

OOP in C++

Object-Oriented Programming in C++

TEMPLATES
Jan 2013 OOP in C++ 165

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 2013 OOP in C++ 166

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 2013 OOP in C++ 167

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 2013

class, (i.e. type), parameters


168

OOP in C++

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 2013 OOP in C++ 169

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 2013 OOP in C++ 170

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 2013

OOP in C++

171

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 2013

OOP in C++

172

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 2013 OOP in C++ 173

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 <chr *>(char *x, char *y) { return ((strcmp(x, y) < 0) ? x : y); }

Jan 2013

OOP in C++

174

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 2013

OOP in C++

175

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 2013

OOP in C++

176

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 2013

OOP in C++

177

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 2013

OOP in C++

178

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 ?
OOP in C++ 179

Jan 2013

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 2013 OOP in C++ 180

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 One-to-many mapping between the instance of a class template and its friend

An unbound friend class template.

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 2013 OOP in C++ 181

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 2013

Not many compiler supports the feature.


OOP in C++ 182

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 2013 OOP in C++ 183

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> Jan 2013 p; OOP in C++ 184

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 2013

OOP in C++

185

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) ; }
186

Jan 2013

OOP in C++

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 2013

OOP in C++

187

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 2013

OOP in C++

188

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 2013

OOP in C++

189

Inheritance vs Templates: Solution


template<typename In, typename out> void process(In& in, Out& out) { // out << in.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.

Merely requires that the passed objects to have suitable interface (such as member function named rdbuf(). )
Jan 2013

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
190

OOP in C++

Another Example
A collection of classes is required for
Stack: for ints , strings, floats etc.
Has operations: push, pop, length of stack. Has features : move, comfort etc each move in diff ways. Each provide different level of comfort.

transportationMode . For airplane, car, boat etc.

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 2013 OOP in C++ 191

Thank You

Vous aimerez peut-être aussi