operator overloading

46
Operator Overloading Back to Fractions...

Upload: fuller

Post on 26-Jan-2016

48 views

Category:

Documents


2 download

DESCRIPTION

Operator Overloading. Back to Fractions. Implementing an Object. We’ve talked at length about object-orientation. We’ve looked heavily at encapsulation and related concerns. We’ve started to implement a data structure for fractions. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Operator Overloading

Operator Overloading

Back to Fractions...

Page 2: Operator Overloading

Implementing an Object

• We’ve talked at length about object-orientation.

– We’ve looked heavily at encapsulation and related concerns.

• We’ve started to implement a data structure for fractions.

– Data structures are special classes/objects designed to organize data within a program.

Page 3: Operator Overloading

Fractions

• As noted earlier, C++ does not have a fraction or rational data type or object class

– This does not mean that we can’t create a class that provides this functionality!

– Let's do it! – Get out laptops and bring up the code we started a couple weeks ago

Page 4: Operator Overloading

Object Requirements

• Our core idea: we want a class of objects that behave like fractions

– What are some of the implications of this?

– What must we store/track?

– What operations should be possible?

– What conversions?

– What about operators?

Page 5: Operator Overloading

Object Requirements

• Our core idea: we want a class of objects that behave like fractions

– Fractions have a numerator and a denominator – we must store these

– We can assign, compare, add, subtract, multiply, and divide fractions

– It would be nice to convert a fraction to an int or a double. How about the reverse directions?

– What about strings?

Page 6: Operator Overloading

Object Requirements

• Our core idea: we want a class of objects that behave like fractions

– Converting to int or double is easy.

– Converting from int is easy

– Converting from double...

… not so much!

– Converting to a string is easy...

… from a string a bit harder

Page 7: Operator Overloading

Object Requirements

• Our core idea: we want a class of objects that behave like fractions

– What about binary operators like +, -?

– We can overload these just like functions!

– How about +=, -=, etc.? Yep!

– How about =, <, >, etc.? Yep, those too!

Page 8: Operator Overloading

Object Requirements

• We need constructors and destructors

• We may also need getters and setters for numerator and denominator

• We can also provide for “automatic” type conversion!

Page 9: Operator Overloading

Implementing Our Object

• Step 1: determining the declarations

– These go in the header (Fraction.h) file.

class Fraction { private: int numerator; int denominator;

public: Fraction(int, int); Fraction();// more later

Page 10: Operator Overloading

Implementing Our Object

• Step 1 (con't): more declarationsFraction add(const Fraction &f) const;Fraction subtract(const Fraction &f) const;Fraction multiply(const Fraction &f) const;Fraction divide(const Fraction &f) const; // comparison methodsint compare(const Fraction &f) const;bool equals(const Fraction &f) const; // conversion methodsint intValue() const;double doubleValue() const;string toString() const;

Page 11: Operator Overloading

Implementing Our Object

Step 1(con't): more declarations

Fraction add(const Fraction &f) const;Fraction subtract(const Fraction &f) const;Fraction multiply(const Fraction &f) const;Fraction divide(const Fraction &f) const;int compare(const Fraction &f) const;bool equals(const Fraction &f) const;int intValue() const;double doubleValue() const;string toString() const;

Note the use of const here -This means that the method willNOT change the object on which

it is called

Page 12: Operator Overloading

Implementing Our Object

Step 1(con't): more declarations

Fraction add(const Fraction &f) const;Fraction subtract(const Fraction &f) const;Fraction multiply(const Fraction &f) const;Fraction divide(const Fraction &f) const;int compare(const Fraction &f) const;bool equals(const Fraction &f) const;int intValue() const;double doubleValue() const;string toString() const;

Note also that we are returningthe object itself rather than

a pointer to the object as before(no *)

Use of string means we must#include <string>

Page 13: Operator Overloading

Implementing Our Object

• Step 2: implementing the methods (goes in Fraction.cpp file).

Fraction::Fraction() : numerator(0), denominator(1) {}

Fraction::Fraction(int n, int d) { numerator = n; denominator = d;}

Wouldn't it be nice if the fractionwere in reduced form?

Solution: implement a privategcd() function in Fraction,

use it to reduce form

Page 14: Operator Overloading

Implementing Our Object

• Revised version of constructor:Fraction::Fraction() : numerator(0), denominator(1) {}

Fraction::Fraction(int n, int d) { int g = gcd(n, d); if (g > 1) { n /= g; d /= g; } numerator = n; denominator = d;}

Page 15: Operator Overloading

Implementing Our Object

• What does gcd look like?int Fraction::gcd(int n, int d) { int n1 = abs(n); // want these positive int n2 = abs(d); int gcd = 1;

for (int k = 1; k <= n1 && k <= n2; ++k) { if (n1 % k == 0 && n2 % k == 0) gcd = k; } return gcd;}

Note: this is a cheesy implementation

of the gcd function!

Remember to putprototype in .h fileas private, static!

Oh yeah! And be sureto #include <cstdlib>in Fraction.cpp file!

Page 16: Operator Overloading

Implementing Our Object

• Step 2: OK – constructors done, now for addition, etc.

(we did this one before, 'member?)

Fraction Fraction::add(const Fraction &f) const{ int num = this->numerator * f.denominator; num += f.numerator * this->denominator; int dnm = f.denominator * denominator;

return Fraction(num, dnm);}

Page 17: Operator Overloading

Implementing Our Object

• Step 2: … subtraction, multiplication,...

Pretty straight-forward…

Fraction Fraction::subtract(const Fraction &f) const{ int num = this->numerator * f.denominator; num -= f.numerator * this->denominator; int dnm = f.denominator * denominator;

return Fraction(num, dnm);}

Page 18: Operator Overloading

Implementing Our Object

• Step 2: … multiplication, division, ...

Fraction Fraction::multiply(const Fraction &f) const{ int num = this->numerator * f.numerator; int dnm = this->denominator * f.denominator;

return Fraction(num, dnm);}

Page 19: Operator Overloading

Implementing Our Object

• Step 2: … division,...

Fraction Fraction::divide(const Fraction &f) const{ // divide is multiply by reciprocal int num = this->numerator * f.denominator; int dnm = this->denominator * f.numerator;

return Fraction(num, dnm);}

Page 20: Operator Overloading

Implementing Our Object

• Step 2: Now for comparison...int Fraction::compare(const Fraction &f) const{ Fraction temp = subtract(f); // difference int num = temp.getNum(); if (num < 0) return -1; // neg => smaller return (num > 0 ? 1 : 0); // pos => bigger}

bool Fraction::equals(const Fraction &f) const{ return(0 == compare(f));}

Page 21: Operator Overloading

Implementing Our Object

• Step 2: Conversion to built-ins ...

Easy peasy

int Fraction::intValue() const{ return (numerator)/(denominator);}

double Fraction::doubleValue() const{ return ((double) numerator )/((double) denominator);}

Page 22: Operator Overloading

Implementing Our Object

• Step 2: … and conversion to stringstring Fraction::toString() const{ stringstream ss; ss << numerator; if (denominator > 1 && numerator != 0) ss << "/" << denominator; return (ss.str());}

What is the if for???

Prevent output like 3/1 and 0/4

Page 23: Operator Overloading

Testing Our Class

• Step 3: Writing some test code

(This goes in testFraction.cpp)

#include <iostream>#include <string>#include "Fraction.h"using namespace std;

int main() { int i; int j; Fraction g1; ...

Page 24: Operator Overloading

Testing Our Class

• Step 3: Writing test code ... Fraction g1;

cout << "Enter two integers: " << flush; cin >> i >> j; g1.setNum(i); // test setters g1.setDenom(j);

cout << "Enter two integers: " << flush; cin >> i >> j; Fraction g2(i,j); // test list constructor ...

Page 25: Operator Overloading

Testing Our Class

• Step 3: Writing test code cout << g1.toString() // test toString << " plus " << g2.toString() << " equals " << g1.add(g2).toString() // test add << endl;

Page 26: Operator Overloading

Testing Our Class

• Step 3: etc. etc. etc. for other 3 fcns,

then do compare: cout << g1.toString() << " compare " << g2.toString() << " is " << g1.compare(g2) << endl;

Page 27: Operator Overloading

Testing Our Class

• Step 3: and equals: cout << g1.toString() << " equals " << g2.toString() << " is " << g1.equals(g2) << endl;

Return 0; // done for now!}

Page 28: Operator Overloading

Exercise 1:

• Implement Fraction class (you should have most of this from before) – just constructors, setters, add(), toString(), and compare() for now...

• Use direct form rather than pointer version

• Compile – no need to have these as 3 files for now... check #includes!!!

• Run test and see that it works

Page 29: Operator Overloading

Review Requirements

• We have met all the basic requirements

Arithmetic operations, comparison, conversion to float, int, and string

• Missing conversion from int, float, or string

• What about operators?

• And automatic conversion?

Page 30: Operator Overloading

Conversion from int

• Automatic (compiler) conversion from other types can occur when a function is called (such as add) that needs another Fraction, but an int or float is the actual parameter

• Compiler will first search for overloaded function with matching signature – not there!

• Then it looks for … constructor!

Page 31: Operator Overloading

Conversion from int

• Step 1: More declarationsclass Fraction { private: int numerator; int denominator; static int gcd(int n, int d);

public: Fraction(int, int); Fraction(); Fraction(int n); // conversion from int ...

Page 32: Operator Overloading

Conversion from int

• Step 2: implementation

Fraction::Fraction(int n){ numerator = n; denominator = 1;}

So what about floats?

Hmmmmmm....

Page 33: Operator Overloading

Overloading Operators

• Wouldn't it be nice to be able to use code like

if (f1 > f2) { … }

• Well, C++ allows this!

• In fact, C++ allows lots of operators to be overloaded

• Use the special operator function

• Named with operator keyword followed by the actual operator

Page 34: Operator Overloading

Overloading Operators

• Step 1: More declarationsclass Fraction { private: int numerator; int denominator; static int gcd(int n, int d);

public: ... bool operator<(const Fraction& f) const; bool operator==(const Fraction& f) const; ...

operator keyword Operator symbol(s)

Page 35: Operator Overloading

Overloading Operators

• Step 2: implementation

bool Fraction::operator<(const Fraction& f) const{ return (compare(f) < 0);}

bool Fraction::operator==(const Fraction& f) const{ return (compare(f) == 0);}

Page 36: Operator Overloading

Testing Operator Overload

• Step 3: Writing some test code... // test overloading < operator cout << g1.toString() << " < " << g2.toString() << " is " << (g1 < g2) << endl; // now test auto conversion from int cout << g1.toString() << " plus 1 equals " << g1.add(1).toString() << endl;...

Page 37: Operator Overloading

Exercise 2:

• Add declarations and implementation for integer conversion and overloading < operator

• Add a little code to test these

• Compile

• Run test and see that it works

Page 38: Operator Overloading

More Operators

• Step 1: More declarationsclass Fraction {...public:... Fraction operator+(const Fraction& f) const; Fraction operator-(const Fraction& f) const; Fraction operator*(const Fraction& f) const; Fraction operator/(const Fraction& f) const;...

operator keyword Operator symbol(s)

Page 39: Operator Overloading

More Operators

• Step 2: implementation

Fraction Fraction::operator+(const Fraction& f) const{ return (add(f));}

Fraction Fraction::operator-(const Fraction& f) const{ return (subtract(f));}

Page 40: Operator Overloading

Augmented Assignment

• What about code like f1 += f2;

• Well, C++ also allows this!

• Issue here is that assignment also returns a Lvalue... how to solve?

• So declare as reference Fraction& and return object

• Can't use const any more!!! Why not?

Page 41: Operator Overloading

AA Operators

• Step 1: More declarationsclass Fraction {...public:... Fraction& operator+=(const Fraction& f) ; Fraction& operator-=(const Fraction& f) ; Fraction& operator*=(const Fraction& f) ; Fraction& operator/=(const Fraction& f) ;

...

reference type return value No more const!

Page 42: Operator Overloading

More Operators

• Step 2: implementation

Fraction& Fraction::operator+=(const Fraction& f){ *this = this->add(f); return *this;}

reference return type so it can be Lvalue

Modify object

Return modified object

Page 43: Operator Overloading

More Testing Overload

• Step 3: Writing some test code... cout << g1.toString() << " plus equal " << g2.toString() << " equals "; g1 += g2; cout << g1.toString() << endl;...

Page 44: Operator Overloading

Exercise 3:

• Add declarations and implementation for overloading + and += operators

• Add a little code to test these

• Compile

• Run test and see that it works

Page 45: Operator Overloading

Operator Overloading

• Can also overload [] indexing operator – see lab

• Only operators that can't be overloaded in C++ are:

?: . .* ::

• Only overload operators when the overloaded function fulfills the logical function of the original operator!

Page 46: Operator Overloading

Questions?

• Project 4:

• Implement overload operators for set and multiset:

+ (union), - (subtraction), +=, -=,

* (intersect), ^ (difference), *=, ^=,

== (equality),

< (proper subset), <= (subset)