Download presentation
Presentation is loading. Please wait.
Published byLionel Parrish Modified over 9 years ago
1
Operator Overloading Back to Fractions...
2
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.
3
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
4
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?
5
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?
6
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
7
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!
8
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!
9
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
10
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; // comparison methods int compare(const Fraction &f) const; bool equals(const Fraction &f) const; // conversion methods int intValue() const; double doubleValue() const; string toString() const;
11
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 will NOT change the object on which it is called
12
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 returning the object itself rather than a pointer to the object as before (no *) Use of string means we must #include
13
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 fraction were in reduced form? Solution: implement a private gcd() function in Fraction, use it to reduce form
14
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; }
15
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 put prototype in.h file as private, static! Oh yeah! And be sure to #include in Fraction.cpp file!
16
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); }
17
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); }
18
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); }
19
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); }
20
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 smaller return (num > 0 ? 1 : 0); // pos => bigger } bool Fraction::equals(const Fraction &f) const { return(0 == compare(f)); }
21
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); }
22
Implementing Our Object Step 2: … and conversion to string string 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
23
Testing Our Class Step 3: Writing some test code (This goes in testFraction.cpp) #include #include "Fraction.h" using namespace std; int main() { int i; int j; Fraction g1;...
24
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...
25
Testing Our Class Step 3: Writing test code cout << g1.toString() // test toString << " plus " << g2.toString() << " equals " << g1.add(g2).toString() // test add << endl;
26
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;
27
Testing Our Class Step 3: and equals: cout << g1.toString() << " equals " << g2.toString() << " is " << g1.equals(g2) << endl; Return 0; // done for now! }
28
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
29
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?
30
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!
31
Conversion from int Step 1: More declarations class Fraction { private: int numerator; int denominator; static int gcd(int n, int d); public: Fraction(int, int); Fraction(); Fraction(int n); // conversion from int...
32
Conversion from int Step 2: implementation Fraction::Fraction(int n) { numerator = n; denominator = 1; } So what about floats? Hmmmmmm....
33
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
34
Overloading Operators Step 1: More declarations class 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)
35
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); }
36
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;...
37
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
38
More Operators Step 1: More declarations class 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)
39
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)); }
40
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?
41
AA Operators Step 1: More declarations class 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!
42
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
43
More Testing Overload Step 3: Writing some test code... cout << g1.toString() << " plus equal " << g2.toString() << " equals "; g1 += g2; cout << g1.toString() << endl;...
44
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
45
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!
46
Questions? Project 4: Implement overload operators for set and multiset: + (union), - (subtraction), +=, -=, * (intersect), ^ (difference), *=, ^=, == (equality), < (proper subset), <= (subset)
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.