Lecture05 operator overloading-and_exception_handling
Upcoming SlideShare
Loading in...5
×
 

Lecture05 operator overloading-and_exception_handling

on

  • 461 views

 

Statistics

Views

Total Views
461
Views on SlideShare
461
Embed Views
0

Actions

Likes
0
Downloads
7
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Lecture05 operator overloading-and_exception_handling Lecture05 operator overloading-and_exception_handling Presentation Transcript

  • Lecture 5 Operator Overloading & Exception HandlingTCP1201 OOPDS 1 1
  • Learning ObjectivesOperator Overloading To understand what is operator overloading To understand the advantage of operator overloading To understand how to overload operators as functionsException 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 wrote 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() const { return num; } int getDen() const { return den; }};Rational multiply (const Rational& r1, const Rational& r2) { int n = r1.getNum() * r2.getNum(); int d = r1.getDen() * r2.getDen(); return Rational (n, d);} 4
  • Operator Overloading Advantage• 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.int main() { Rational r1(1,2), r2(1,3), r3(5,6), r4; r4 = multiply(r1, multiply(r2,r3)); Complex ...• If we overload multiply operator *, we can write:int main() { Rational r1(1,2), r2(1,3), r3(5,6), r4; Simple & r4 = r1 * r2 * r3; easy to ... understand 5
  • C++ OperatorsOperators in C++ are divided into 2 categories based on thenumber 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++ OperatorsSome unary operators can be used as both prefix and postfixoperators, e.g. increment ‘++’ and decrement ‘--’ operators. int a = b = 0; ++a; // a = 1 prefix b = ++a; // b = 2, a = 2 cout << "a is:" << a; // a is 2 cout << "b is:" << b; // b is 2 postfix b = a++; // b = 2 // a = 3 cout << "a is:" << a; // a is 3 cout << "b is:" << b; // b is 2 7
  • How to Overload Operators?We overload an operator by writing a special function withthe keyword operatorS, where S is an operator symbol (+, -, *, /, !, ++, etc.).We should overload an operator in a sensible way and meetgeneral expectation, e.g. dont overload * operator toperform division. returntype operatorS (parameters) { ... return something; } // For our Rational number multiplication. returntype operator* (parameters) { ... return something; 8 }
  • How to Overload Operators?The number of parameters depend whether the overloadedoperator is unary or binary.• Unary operator has 1 parameter.• Binary operator has 2 parameters.Since operator * is a binary operator hence the number ofparameter is 2.We are multiplying 2 Rational objects and expecting theresult is also a Rational object, hence the data type ofboth parameter and return type should be Rational. // For our Rational number multiplication. Rational operator* (Rational, Rational) { ... return Rational(); // return a new object. } 9
  • Parameters & Return Types• For parameters, use references whenever possible (especially when the parameter is a big object).• Always use pass-by-const reference when the argument will not be modified.• 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.• Operators that return a reference to the original object should return a non-const reference to ensure that the result can be modified in a later operation., e.g. <<, >>, =, etc. 10
  • Overloading Operator* as Non-Friend Functionclass Rational { Binary operator has int num; 2 parameters. int den; public: int main() { Rational (int num = 0, int den = 1) Rational r1(1,2), : num(num), den(den) {} r2(1,3), void print() const { r3(5,6), cout << num << "/" << den << endl; r4; r4 = r1 * r2 * r3; } r1.print(); int getNum() const { return num; } r2.print(); int getDen() const { return den; } r3.print();}; r4.print();Rational operator* (const Rational& r1, } const Rational& r2) { int n = r1.getNum() * r2.getNum(); Output: 1/2 int d = r1.getDen() * r2.getDen(); 1/3 return Rational (n, d); // Return a new 5/6 // Rational object 5/36} 11
  • Overloading Operator* as Friend Functionclass Rational { Binary operator has 2 friend Rational operator* (const Rational&, parameters. const Rational&); int num; int main() { int den; Rational r1(1,2), public: r2(1,3), Rational (int num=0, int den=1) r3(5,6), : num(num), den(den) {} r4; r4 = r1 * r2 * r3; void print() const { r1.print(); cout << num << "/" r2.print(); << den << endl; r3.print(); } r4.print();}; }Rational operator* (const Rational& r1, Output: const Rational& r2) { 1/2 int n = r1.num * r2.num; 1/3 int d = r1.den * r2.den; 5/6 return Rational (n, d); // Return a new 5/36 // Rational object} 12
  • Overloading Operator<< and >>Binary operator as function has 2 parameters int main() { Rational r1,class Rational { r2, friend istream& operator>> (istream&, Rational&); r3; ... cin >> r1}; >> r2;istream& operator>> (istream& is, Rational& r) { r3 = r1 * r2; is >> r.num >> r.den; cout<< r1<<endl // r.getNum() & r.getDen() wont work. Why? << r2<<endl return is; << r3;} }ostream& operator<< (ostream& os, const Rational& r) { Output: os << r.getNum() << "/" << r.getDen(); 1 2 3 4 return os; 1/2} 3/4 3/8 13
  • The Increment Operator (‘++’)Is a unary operator that can be used as both a prefix ( ++x)and postfix (x++) operator.If we have overloaded both prefix and postfix versions of theincrement operator for class Rational:• A prefix call to operator (++x) will generate a call to: Rational::operator++() // prefix• A postfix call to operator (x++) will generate a call to: Rational::operator++(int) // postfixPostfix requires 1 int parameter to differentiate itself fromprefix. 14
  • Overloading Operator<Binary operator has 2 parameters.class Rational { ...};bool operator< (const Rational& r1, const Rational&r2) { return r1.getNum() * r2.getDen() < r1.getDen() * r2.getNum();}int main() { Rational r1(1,2), r2(2,3), r3(1,2); if (r1 < r2) cout << "r1 is smaller than r2n"; else cout << "r1 is NOT smaller than r2n"; if (r1 < r3) cout << "r1 is smaller than r3n"; else cout << "r1 is NOT smaller than r3n";}Output:r1 is smaller than r2r1 is NOT smaller than r3 15
  • Overloading Operator()To sort an array or vector of your class by different attribute atdifferent time. int main() {class Point { Point pts[3] = int x, y; {Point(3,6), public: Point(5,4), Point (int x = 0, int y = 0) : x(x), y(y) { } Point(1,2)}; int getX() const { return x; } for (int i=0; i<3; i++) cout << pts[i] << " "; int getY() const { return y; } cout << endl;}; sort (pts, pts+3,ostream& operator<< (ostream& os, const Point& p) { SortByX()); os << "(" << p.getX() << ", " << p.getY() << ")"; for (int i=0; i<3; i++) return os; cout << pts[i] << " "; cout << endl;} sort (pts, pts+3,struct SortByX { SortByY()); bool operator() (const Point& p1, const Point& p2) for (int i=0; i<3; i++) { return p1.getX() < p2.getX(); } cout << pts[i] << " ";}; }struct SortByY { Output: bool operator() (const Point& p1, const Point& p2) (3, 6) (5, 4) (1, 2) { return p1.getY() < p2.getY(); } (1, 2) (3, 6) (5, 4)}; (1, 2) (5, 4) (3, 6) 16
  • Exception HandlingWhen a program is executed, unexpected situations mayoccur. Such situations are called exceptions.In other word: An exception is a runtime error caused bysome abnormal conditions.Example:• Division by zero• Failure of new operator to obtain a requested amount of memoryException handler is code that handles the exception(runtime error) when it occurs. 17
  • Exception Example: Division By Zero How to deal with the error below?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);} 18
  • Exception Example: Division By ZeroA solution is shown below. It works but the codes thathandles the error mixes with the codes for division, makingthe codes harder to read (is if for division and else forerror handling, or the other way? No direct indication fromif/else keywords alone.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 zeron"; else cout << "Result = " << divide (x, y);} 19
  • Exception HandlingC++ implements exception handling using try, throw andcatch block.try block:• Write the code that might generate runtime error within the try block. try { // Code that may generate exceptions. ... if (<error condition is true>) throw <Exception object>; ... } catch (<Exception type>) { // Error handling code. ... } 20
  • try, throw, and catch blocksthrow 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 { // Code that may generate exceptions. ... if (<error condition is true>) throw <Exception object>; // Jump to catch block. ... // Will be skipped if throw statement is executed.}catch (<Exception type>) { // Error handling code. ...} 21
  • try, throw, and catch blocks 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 { // Code that may generate exceptions. ... if (<error condition is true>) throw <Exception object>; ...}// No code here.catch (<Exception type>) { // Thrown exception object must // match caught exception type. // Error handling code. ...} 22
  • Example: try, throw, and catch blocksdouble divide (double x, double y) { if (y == 0) If there is an exception, throw y; throw it. return x / y;} Put code that mayint main() { generate error in double x, y; try block. cin >> x >> y; try { If there is no exception, double result = divide (x, y); cout << "Result = " << result; resume execution. } catch (double a) { If there is an exception cout << "Cannot divide by zeron"; of type double, } catch it.} 23
  • Example: try, throw, and catch blocksdouble divide (double x, double y) { Output1:No exception if (y == 0) 1 2 throw y; Result = 0.5 return x / y;}int main() { Output2:With exception double x, y; 1 0 cin >> x >> y; Cannot divide by zero try { double result = divide (x, y); cout << "Result = " << result; } catch (double a) { When an exception is cout << "Cannot divide by zeron"; thrown, the codes } that appear after the} throw statement in the try block is skipped. 24
  • Example: try, throw, and catch blocksdouble divide (double x, double y) { Output1:No exception if (y == 0) 1 2 throw y; Result = 0.5 return x / y;}int main() { Output2:With exception double x, y; 1 0 cin >> x >> y; Cannot divide by zero try { double result = divide (x, y); cout << "Result = " << result; } catch (double a) { The type of the object cout << "Cannot divide by zeron"; being thrown must } match the type of the} parameter in the catch block 25
  • Example: try, throw, and catch blocksdouble divide (double x, double y) { Output1:No exception if (y == 0) 1 2 throw y; Result = 0.5 return x / y;}int main() { Output2:With exception double x, y; 1 0 cin >> x >> y; terminate called after try { throwing an instance of double result = divide (x, y); double cout << "Result = " << result; } catch (int a) { If the type of object cout << "Cannot divide by zeron"; being thrown does } not match the type of} the parameter in the catch block, 26
  • Example: try, throw, and catch blocksNote that exception handling does not require a function towork.int main() { double x, y; cin >> x >> y; try { if (y == 0) throw y; Output1:No exception double result = x / y; 1 2 cout << "Result = " << result; Result = 0.5 } catch (double a) { cout << "Cannot divide by zeron"; Output2:With exception } 1 0} Cannot divide by zero 27
  • Exception PropagationIf the function containing the throw statement does notcatch the exception, the exception will be propagated up tothe caller of the function until it reaches a try block or themain function.In the former case, the try/catch block of the callerhandles the exception if the exception type matches one ofthe catch block. Otherwise the exception will bepropagated up again.If the exception reaches the main function and is nothandled, the program will be terminated. 28
  • Example: Exception Propagationdouble f2(double x, double y) { Output:With exception if (y == 0) throw y; return x / y; 1 0} Cannot divide by zerodouble f1(double x, double y) { return f2(x, y);} The exception isdouble divide (double x, double y) { propagated in the return f1(x, y); following order:} f2(), f1(),int main() { divide(), ... main(). try { double result = divide (x, y); The main() catches cout << "Result = " << result; and handles the } catch (double a) { exception. ... 29
  • Multiple catch BlocksSometimes, we might have many different exceptionsfor a small block of code.try { ... if (<Error1>) throw <Object of exception type1>; if (<Error2>) throw <Object of exception type2>; if (<Error3>) throw <Object of exception type3>; ...}catch (<Exception type1>) { // Code that resolves a type1 exception.}catch (<Exception type2>) { // Code that resolves a type2 exception.}catch (<Exception type3>) { // Code that resolves a typeN exception.} 30
  • Multiple catch BlocksBut, which catch block will be instigated/invoked?Depend on the type of exception object.The type must match exactly, no implicit conversion willbe done by C++. Type double does not match with typeint.Only one catch block will be executed for an exception.The catch block that first matches the exception typewould be chosen. 31
  • Multiple catch Blocksvoid func (int n) { int main () { try { func (1); if (n == 1) throw 11; // int func (3); if (n == 3) throw 3.5; // double func (4); cout << "n is not 1 or 3n"; } } catch (double a) { // Wont catch int Output: cout << "Catch double " << a << endl; Catch int 11 } Catch double 3.5 catch (int a) { // Match int n is not 1 or 3 cout << "Catch int " << a << endl; }} No implicit conversion of exception type in catch argument 32
  • Exception MatchingTo catch every possible exception type, use ellipsis "…". try { ... } catch (...) { // catches ALL exception types. ... } Limitations of catch (...): • You cant tell what type of exception occurred. • No argument to reference. • Should always be placed as the last catch block. 33
  • Exception Matchingvoid func (int n) { int main () { try { func (1); if (n == 1) throw 11; // int func (2); if (n == 2) throw string("abc"); func (3); if (n == 3) throw 3.5; // double func (4); cout << "n is not 1, 2 or 3n"; } } catch (double a) { cout << "Catch double " << a << endl; Output: } Not double nor string catch (string a) { Catch string abc cout << "Catch string " << a << endl; Catch double 3.5 } n is not 1, 2 or 3 catch (...) { // all types cout << "Not double nor stringn"; }} 34
  • Advantages of Exception HandlingUsing try, throw, and catch blocks to handleexception 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. 35