Operator Overloading & Exception Handling TCP1201 OOPDS 1 Lecture 5 1.

Slides:



Advertisements
Similar presentations
Overloading Operators Overloading operators Unary operators Binary operators Member, non-member operators Friend functions and classes Function templates.
Advertisements

Lecture 9. 2 Exception  An exception is a unusual, often unpredictable event, detectable by software or hardware, that requires special processing occurring.
Exception Handling The purpose of exception handling is to permit the program to catch and handle errors rather than letting the error occur and suffer.
1 Chapter 17-2 Templates and Exceptions Dale/Weems.
Exceptions, Templates, And The Standard Template Library (STL) Chapter 16.
CSE 332: C++ exceptions Overview of C++ Exceptions Normal program control flow is halted –At the point where an exception is thrown The program call stack.
Copyright © 2012 Pearson Education, Inc. Chapter 16: Exceptions, Templates, and the Standard Template Library (STL)
Lesson 16 Exceptions Lesson Exceptions1. Murphy’s Law Anything that can go wrong will go wrong Lesson Exceptions2.
Exception Handling. Introduction One benefit of C++ over C is its exception handling system. An exception is a situation in which a program has an unexpected.
Jerry Lebowitz. Topics  Provides a facility for a systematic object oriented approach to handling runtime errors ◦ Can also handle runtime errors.
Exceptions Briana B. Morrison CSE 1302C Spring 2010.
Overloading Operators Object-Oriented Programming Using C++ Second Edition 8.
Class and Objects.
 2006 Pearson Education, Inc. All rights reserved Operator Overloading.
© Copyright Eliyahu Brutman Programming Techniques Course Version 1.0.
Exceptions Objectives At the conclusion of this lesson, students should be able to Explain the need for exceptions Correctly write programs that use.
Operator OverloadingCS-2303, C-Term Operator Overloading CS-2303 System Programming Concepts (Slides include materials from The C Programming Language,
Operator Overloading 1. Introduction Let’s define a class for Complex numbers: class Complex { private: double real, image; public: Complex () : real(0.0),
Exceptions. Many problems in code are handled when the code is compiled, but not all Some are impossible to catch before the program is run  Must run.
Introduction to C++ Templates and Exceptions l C++ Function Templates l C++ Class Templates l Exception and Exception Handler.
1 Operator Overloading in C++ Copyright Kip Irvine, All rights reserved. Only students enrolled in COP 4338 at Florida International University may.
Chapter 12: Adding Functionality to Your Classes.
What is an exception? An exception is: – an event that interrupts the normal processing of the program. –an error condition that violates the semantic.
1 Chapter Eight Exception Handling. 2 Objectives Learn about exceptions and the Exception class How to purposely generate a SystemException Learn about.
Object Oriented Programming
C++ Exceptions STL Vector. Example int Quotient (int numer, int denom} { if (denom != 0) return (numer/denom); else //What to do?? }
1 CSC241: Object Oriented Programming Lecture No 27.
1 Overloading Operators Object-Oriented Programming Using C++ Second Edition 8.
COSC 1P03 Data Structures and Abstraction 4.1 Abstract Data Types The advantage of a bad memory is that one enjoys several times the same good things for.
Object Oriented Programming Elhanan Borenstein Lecture #4.
Case Study - Fractions Timothy Budd Oregon State University.
Introduction to Classes in C++
1 Overloading Overloading allows a function or operator to have a different meaning depending on the type of objects it is used on. Examples: operator+
Concordia University Department of Computer Science and Software Engineering Click to edit Master title style ADVANCED PROGRAM DESIGN WITH C++ Part 9:
Chapter 8 Operator Overloading, Friends, and References.
CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element.
©Fraser Hutchinson & Cliff Green C++ Certificate Program C++ Intermediate Operator Overloading.
Slide 1 Chapter 8 Operator Overloading, Friends, and References.
Exceptions in C++. Exceptions  Exceptions provide a way to handle the errors generated by our programs by transferring control to functions called handlers.
CSE 332: C++ Statements C++ Statements In C++ statements are basic units of execution –Each ends with ; (can use expressions to compute values) –Statements.
Exceptions and Program Correctness based on the original work by Dr. Roger deBry Version 1.1.
CS212: Object Oriented Analysis and Design Lecture 19: Exception Handling.
Exception-Handling Fundamentals  A Java exception is an object that describes an exceptional (that is, error) condition that has occurred in a piece of.
CSCI 383 Object-Oriented Programming & Design Lecture 20 Martin van Bommel.
Exception Handling How to handle the runtime errors.
Array and Pointers An Introduction Unit Unit Introduction This unit covers the usage of pointers and arrays in C++
Introduction to Exceptions in Java CS201, SW Development Methods.
CSE 332: C++ Exceptions Motivation for C++ Exceptions Void Number:: operator/= (const double denom) { if (denom == 0.0) { // what to do here? } m_value.
Asif Nawaz University Institute of Information Technology, PMAS-AAUR Lecture 05: Object Oriented Programming:2014 Object-Oriented Programming in C++ Exception.
CSE1002 – Problem Solving with Object Oriented Programming
Operator Overloading Introduction
Exceptions.
Andy Wang Object Oriented Programming in C++ COP 3330
Exceptions, Templates, and the Standard Template Library (STL)
Object-Oriented Programming (OOP) Lecture No. 21
Why exception handling in C++?
The dirty secrets of objects
Exceptions with Functions
Andy Wang Object Oriented Programming in C++ COP 3330
Exceptions and Templates
Exception Handling.
Exceptions 1 CMSC 202.
Standard Version of Starting Out with C++, 4th Edition
CISC/CMPE320 - Prof. McLeod
Exceptions, Templates, and the Standard Template Library (STL)
COP 3330 Object-oriented Programming in C++
Object-Oriented Programming (OOP) Lecture No. 43
Lecture 9.
Exception Handling.
CMSC 202 Lesson 20 Exceptions 1.
Presentation transcript:

Operator Overloading & Exception Handling TCP1201 OOPDS 1 Lecture 5 1

Learning Objectives Operator Overloading  To understand what is operator overloading  To understand the advantage of operator overloading  To understand how to overload operators as functions Exception handling  To understand what is exception  To realize the advantages of exception handling  To understand the use of try, throw and catch block  To understand how exception propagation works  To understand how to write multiple catch blocks and exception matching 2

Operator Overloading Add capability to an operator via writing a new "special function" for the same operator but with different data types and combinations of parameters. For example, C++'s operator '+': C++ has built-in support for using operator '+' to add int or double, and also for concatenating string. However using operator '+' to add 2 objects of your (user-defined) class is not automatically supported. We can write a "function" to make C++ support adding 2 objects of user-defined class. This process is called operator overloading. 3

Operator Overloading Advantage It provides a simpler way for doing some operations on user-defined classes. Consider the following Rational class which represents a rational/fraction number, e.g. 1/2, 2/3: class Rational { int num; // numerator int den; // denominator public: Rational (int num=0, int den=1) : num(num), den(den) {} int getNum() { return num; } int getDen() { return den; } }; 4 Rational multiply (Rational& r1, Rational& r2) { } int n = r1.getNum() * r2.getNum(); int d = r1.getDen() * r2.getDen(); return Rational (n, d);

To multiply rational numbers e.g. 1/2 * 1/3 * 5/6 = 5/36, we can use the method multiply(), but it looks more complex. If we overload multiply operator '*', we can write: int main() { Rational r1(1,2), r2(1,3), r3(5,6), r4; r4 = multiply(r1, multiply(r2,r3));... int main() { Rational r1(1,2), r2(1,3), r3(5,6), r4; r4 = r1 * r2 * r3;... Simple & easy to understand Complex Operator Overloading Advantage 5

Operators in C++ are divided into 2 categories based on the number of arguments they accept: Unary operators accept one argument x++, --x, !x, etc. Binary operators accept two arguments x+y, x-y, x*y, x<y, x=y, etc. C++ Operators

Some unary operators can be used as both prefix and postfix operators, e.g. increment ‘++’ and decrement ‘--’ operators. int a = b = 0; ++a; // a = 1 b = ++a; // b = 2, a = 2 cout << "a is:" << a; // a is 2 cout << "b is:" << b; // b is 2 b = a++; // b = 2 // a = 3 cout << "a is:" << a; // a is 3 cout << "b is:" << b; // b is 2 prefix postfix C++ Operators 7

We overload an operator by writing a special function with the keyword operatorS, where S is an operator symbol (+, -, *, /, !, ++, etc.). We should overload an operator in a sensible way and meet general expectation, e.g. don't overload '*' operator to perform division. How to Overload Operators? returntype operatorS (parameters) {... return something; } 8 // For our Rational number multiplication. returntype operator* (parameters) {... return something; }

The number of parameters depend whether the overloaded operator is unary or binary. Unary operator has 1 parameter. Binary operator has 2 parameters. Since operator '*' is a binary operator hence the number of parameter is 2. We are multiplying 2 Rational objects and expecting the result is also a Rational object, hence the data type of both parameter and return type should be Rational. How to Overload Operators? 9 // For our Rational number multiplication. Rational operator* (Rational, Rational) {... return Rational(); // return a new object. }

Overloading Operator '*' as Non-Friend Function class Rational { int num; int den; public: Rational (int num = 0, int den = 1) : num(num), den(den) {} void print() { cout << num << "/" << den << endl; } int getNum() { return num; } int getDen() { return den; } }; Rational operator* (Rational& r1, Rational& r2) { int n = r1.getNum() * r2.getNum(); int d = r1.getDen() * r2.getDen(); return Rational (n, d); // Return a new // Rational object } int main() { Rational r1(1,2), r2(1,3), r3(5,6), r4; r4 = r1 * r2 * r3; r1.print(); r2.print(); r3.print(); r4.print(); } Output: 1/2 1/3 5/6 5/36 Non-friend function call methods. 10

friend Access Privilege class Rational { friend Rational operator* (Rational&, Rational&); int num, den;... }; Rational operator* (Rational& r1, Rational& r2) { int n = r1.num * r2.num; // Directly access private member. int d = r1.den * r2.den; return Rational (n, d); } If class A grants a global function (not a method) or another class B (not subclass) a friend access privilege, it means that class A allows the global function or class B to access its private members. This actually violates encapsulation but is generally accepted when doing operator overloading. A friend function is not a method of the class. 11

Overloading Operator '*' as Friend Function class Rational { friend Rational operator* (Rational&, Rational&); int num; int den; public: Rational (int num=0, int den=1) : num(num), den(den) {} void print() { cout << num << "/" << den << endl; } }; Rational operator* (Rational& r1, Rational& r2) { int n = r1.num * r2.num; int d = r1.den * r2.den; return Rational (n, d); // Return a new // Rational object } int main() { Rational r1(1,2), r2(1,3), r3(5,6), r4; r4 = r1 * r2 * r3; r1.print(); r2.print(); r3.print(); r4.print(); } Output: 1/2 1/3 5/6 5/36 Friend function can access private member directly. 12

istream& operator>> (istream& is, & p) { is >> ; return is; // Return existing object instead of new object. } ostream& operator & p) { os ; return os; // Return existing object instead of new object. } Overloading Operator ' >' Both insertion operator ' >' are binary operators because they need 2 arguments to work. They usually have the following pattern (return type and first parameter) regardless of the class you want to overload. Your job is to figure out your class and the code for cin or cout. 13

class Rational { friend istream& operator>> (istream&, Rational&);... }; istream& operator>> (istream& is, Rational& r) { is >> r.num >> r.den; // r.getNum() & r.getDen() won't work. Why? return is; } int main() { Rational r1, r2, r3; cin >> r1 >> r2; r3 = r1 * r2; cout<< r1<<endl << r2<<endl << r3; } Output: /2 3/4 3/8 Overloading Operator ' >' Overloading ' >' allows us to use them on object of user-defined class. 14 ostream& operator<< (ostream& os, Rational& r) { os << r.getNum() << "/" << r.getDen(); return os; }

Parameters & Return Types For parameters, use references whenever possible (especially when the parameter is a big object). Always try to follow the spirit of the built-in implementations, e.g. comparison operators (==, !=, >, etc) generally return a bool, so an overloaded version should do the same. 15

Increment Operator '++' Is a unary operator that can be used as both a prefix ( ++x) and postfix (x++) operator. How does compiler know whether we are overloading prefix or postfix? Use our Rational class as example: The function prototype for overload prefix operator: The function prototype for overloading postfix operator: Postfix requires 1 int parameter to differentiate itself from prefix. Rational operator++(Rational &) // prefix Rational operator++(Rational &, int) // postfix 16

class Rational {... }; bool operator< (Rational& r1, Rational& r2) { return r1.getNum()*r2.getDen() < r1.getDen()*r2.getNum(); } Overloading Operator '<' Binary operator '<' is for comparing 2 arguments. Hence it should return a Boolean result. 17 int main() { Rational r1(1,2), r2(2,3), r3(1,2); if (r1 < r2) cout << "r1 is smaller than r2\n"; else cout << "r1 is NOT smaller than r2\n"; if (r1 < r3) cout << "r1 is smaller than r3\n"; else cout << "r1 is NOT smaller than r3\n"; } Output: r1 is smaller than r2 r1 is NOT smaller than r3

#include // sort()... class Point { int x, y; public: Point (int x = 0, int y = 0) : x(x), y(y) { } int getX() const { return x; } int getY() const { return y; } }; ostream& operator<< (ostream& os, Point& p) { os << "(" << p.getX() << ", " << p.getY() << ")"; return os; } int main() { Point pts[3] = {Point(3,6), Point(5,4), Point(1,2)}; for (int i=0; i<3; i++) cout << pts[i] << " "; cout << endl; } Overloading Operator '()' To sort an array or vector of your class by different attribute at different time. 18 class SortByX { public: bool operator()(const Point& p1, const Point& p2) { return p1.getX() < p2.getX(); } }; class SortByY { public: bool operator() (const Point& p1, const Point& p2) { return p1.getY() < p2.getY(); } }; sort (pts, pts+3, SortByX()); for (int i=0; i<3; i++) cout << pts[i] << " "; cout << endl; sort (pts, pts+3, SortByY()); for (int i=0; i<3; i++) cout << pts[i] << " "; (1, 2) (5, 4) (3, 6) (1, 2) (3, 6) (5, 4) Output: (3, 6) (5, 4) (1, 2)

Exception Handling When a program is executed, unexpected situations may occur. Such situations are called exceptions. In other word: An exception is a runtime error caused by some abnormal conditions. Example: Division by zero Failure of new operator to obtain a requested amount of memory Exception handler is code that handles the exception (runtime error) when it occurs. 19

Exception Example: Division By Zero double divide (double x, double y) { return x / y; // divide by 0 if y = 0 } int main() { double x, y; cin >> x >> y; cout << "Result = " << divide (x, y); } How to deal with the error below? 20

Exception Example: Division By Zero double divide (double x, double y) { return x / y; // divide by 0 if y = 0 } int main() { double x, y; cin >> x >> y; if (y == 0) cout << "Cannot divide by zero\n"; else cout << "Result = " << divide (x, y); } A solution is shown below. It works but the codes that handles the error mixes with the codes for division, making the codes harder to read (is if for division and else for error handling, or the other way?) 21

C++ implements exception handling using try, throw and catch block. try block: Write the code that might generate runtime error within the try block. Exception Handling 22 try { // Code that may generate exceptions.... }

throw statement: Use keyword throw in try block to signal that abnormal condition or error has occurred. If the throw statement is executed, the C++ runtime will skip the remaining of the try block, and jump to the catch block to continue execution. try, throw, and catch blocks 23 try { // Code that may generate exceptions.... if ( ) throw ; // Jump to catch block.... // Will be skipped if throw statement is executed. }

catch block: Write the code that catches the thrown exception object in catch block. This is the exception handler. Unhandled/Uncaught thrown exception will terminate the program. try, throw, and catch blocks 24 try { // Code that may generate exceptions.... if ( ) throw ; // Jump to catch block.... // Will be skipped if throw statement is executed. } // No code here. catch ( ) { // Thrown exception object must // match caught exception type.... }

double divide (double x, double y) { if (y == 0) throw y; return x / y; } int main() { double x, y; cin >> x >> y; try { double result = divide (x, y); cout << "Result = " << result; } catch (double a) { cout << "Cannot divide by zero\n"; } If there is an exception, throw it. Put code that may generate error in try block. If there is no exception, resume execution. If there is an exception of type double, catch it. Example: try, throw, and catch blocks 25

double divide (double x, double y) { if (y == 0) throw y; return x / y; } int main() { double x, y; cin >> x >> y; try { double result = divide (x, y); cout << "Result = " << result; } catch (double a) { cout << "Cannot divide by zero\n"; } Output1:No exception 1 2 Result = 0.5 Output2:With exception 1 0 Cannot divide by zero When an exception is thrown, the codes that appear after the throw statement in the try block is skipped. Example: try, throw, and catch blocks 26

double divide (double x, double y) { if (y == 0) throw y; return x / y; } int main() { double x, y; cin >> x >> y; try { double result = divide (x, y); cout << "Result = " << result; } catch (double a) { cout << "Cannot divide by zero\n"; } Example: try, throw, and catch blocks Output1:No exception 1 2 Result = 0.5 Output2:With exception 1 0 Cannot divide by zero The type of the object being thrown must match the type of the parameter in the catch block 27

double divide (double x, double y) { if (y == 0) throw y; return x / y; } int main() { double x, y; cin >> x >> y; try { double result = divide (x, y); cout << "Result = " << result; } catch (int a) { cout << "Cannot divide by zero\n"; } Example: try, throw, and catch blocks Output1:No exception 1 2 Result = 0.5 Output2:With exception 1 0 terminate called after throwing an instance of 'double' If the type of object being thrown does not match the type of the parameter in the catch block, 28

int main() { double x, y; cin >> x >> y; try { if (y == 0) throw y; double result = x / y; cout << "Result = " << result; } catch (double a) { cout << "Cannot divide by zero\n"; } Example: try, throw, and catch blocks Output1:No exception 1 2 Result = 0.5 Output2:With exception 1 0 Cannot divide by zero Note that exception handling does not require a function to work. 29

Exception Propagation If the function containing the throw statement does not catch the exception, the exception will be propagated up to the caller of the function until it reaches a try block or the main function. In the former case, the try/catch block of the caller handles the exception if the exception type matches one of the catch block. Otherwise the exception will be propagated up again. If the exception reaches the main function and is not handled, the program will be terminated. 30

Example: Exception Propagation double f2(double x, double y) { if (y == 0) throw y; return x / y; } double f1(double x, double y) { return f2(x, y); } double divide (double x, double y) { return f1(x, y); } int main() {... try { double result = divide (x, y); cout << "Result = " << result; } catch (double a) {... Output:With exception 1 0 Cannot divide by zero The exception is propagated in the following order: f2(), f1(), divide(), main(). The main() catches and handles the exception. 31

Sometimes, we might have many different exceptions for a small block of code. Multiple catch Blocks 32 try {... if ( ) throw ;... } catch ( ) { // Code that resolves a type1 exception. } catch ( ) { // Code that resolves a type2 exception. } catch ( ) { // Code that resolves a typeN exception. }

Sometimes, we might have many different exceptions for a small block of code. Multiple catch Blocks 33 try {... if ( ) throw ;... } catch ( ) { // Code that resolves a type1 exception. } catch ( ) { // Code that resolves a type2 exception. } catch ( ) { // Code that resolves a typeN exception. }

Sometimes, we might have many different exceptions for a small block of code. Multiple catch Blocks 34 try {... if ( ) throw ;... } catch ( ) { // Code that resolves a type1 exception. } catch ( ) { // Code that resolves a type2 exception. } catch ( ) { // Code that resolves a typeN exception. }

But, which catch block will be instigated/invoked? Depend on the type of exception object. The type must match exactly, no implicit conversion will be done by C++. Type double does not match with type int. Only one catch block will be executed for an exception. The catch block that first matches the exception type would be chosen. Multiple catch Blocks 35

int main () { func (1); func (3); func (4); } Output: Catch int 11 Catch double 3.5 n is not 1 or 3 void func (int n) { try { if (n == 1) throw 11; // int if (n == 3) throw 3.5; // double cout << "n is not 1 or 3\n"; } catch (double a) { // Won't catch int cout << "Catch double " << a << endl; } catch (int a) { // Match int cout << "Catch int " << a << endl; } No implicit conversion of exception type in catch argument Multiple catch Blocks 36

Exception Matching To catch every possible exception type, use ellipsis "…". Limitations of catch (...): You can't tell what type of exception occurred. No argument to reference. Should always be placed as the last catch block. try {... } catch (...) { // catches ALL exception types.... } 37

Exception Matching int main () { func (1); func (2); func (3); func (4); } Output: Not double nor string Catch string abc Catch double 3.5 n is not 1, 2 or 3 void func (int n) { try { if (n == 1) throw 11; // int if (n == 2) throw string("abc"); if (n == 3) throw 3.5; // double cout << "n is not 1, 2 or 3\n"; } catch (double a) { cout << "Catch double " << a << endl; } catch (string a) { cout << "Catch string " << a << endl; } catch (...) { // all types cout << "Not double nor string\n"; } 38

Advantages of Exception Handling Using try, throw, and catch blocks to handle exception offer the following advantages: 1.Provide clarify on the section of codes that handle the error. 2.You may throw an exception in a function/method, and handle it somewhere else. 39