Some of the most commonly used operators in C++ are the arithmetic operators -- that is, the plus operator (+), minus operator (-), multiplication operator (*), and division operator (/). Note that all of the arithmetic operators are binary operators -- meaning they take two operands -- one on each side of the operator. All four of these operators are overloaded in the exact same way.

It turns out that there are three different ways to overload operators: the member function way, the friend function way, and the normal function way. In this lesson, we’ll cover the friend function way (because it’s more intuitive for most binary operators). Next lesson, we’ll discuss the normal function way. Finally, in a later lesson in this chapter, we’ll cover the member function way. And, of course, we’ll also summarize when to use each in more detail.

Overloading operators using friend functions

Consider the following trivial class:

1 2 3 4 5 6 7 8 9 |
class Cents { private: int m_cents; public: Cents(int cents) { m_cents = cents; } int getCents() const { return m_cents; } }; |

The following example shows how to overload operator plus (+) in order to add two “Cents” objects together:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#include <iostream> class Cents { private: int m_cents; public: Cents(int cents) { m_cents = cents; } // add Cents + Cents using a friend function friend Cents operator+(const Cents &c1, const Cents &c2); int getCents() const { return m_cents; } }; // note: this function is not a member function! Cents operator+(const Cents &c1, const Cents &c2) { // use the Cents constructor and operator+(int, int) // we can access m_cents directly because this is a friend function return Cents(c1.m_cents + c2.m_cents); } int main() { Cents cents1{ 6 }; Cents cents2{ 8 }; Cents centsSum{ cents1 + cents2 }; std::cout << "I have " << centsSum.getCents() << " cents.\n"; return 0; } |

This produces the result:

I have 14 cents.

Overloading the plus operator (+) is as simple as declaring a function named operator+, giving it two parameters of the type of the operands we want to add, picking an appropriate return type, and then writing the function.

In the case of our Cents object, implementing our operator+() function is very simple. First, the parameter types: in this version of operator+, we are going to add two Cents objects together, so our function will take two objects of type Cents. Second, the return type: our operator+ is going to return a result of type Cents, so that’s our return type.

Finally, implementation: to add two Cents objects together, we really need to add the m_cents member from each Cents object. Because our overloaded operator+() function is a friend of the class, we can access the m_cents member of our parameters directly. Also, because m_cents is an integer, and C++ knows how to add integers together using the built-in version of the plus operator that works with integer operands, we can simply use the + operator to do the adding.

Overloading the subtraction operator (-) is simple as well:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
#include <iostream> class Cents { private: int m_cents; public: Cents(int cents) { m_cents = cents; } // add Cents + Cents using a friend function friend Cents operator+(const Cents &c1, const Cents &c2); // subtract Cents - Cents using a friend function friend Cents operator-(const Cents &c1, const Cents &c2); int getCents() const { return m_cents; } }; // note: this function is not a member function! Cents operator+(const Cents &c1, const Cents &c2) { // use the Cents constructor and operator+(int, int) // we can access m_cents directly because this is a friend function return Cents(c1.m_cents + c2.m_cents); } // note: this function is not a member function! Cents operator-(const Cents &c1, const Cents &c2) { // use the Cents constructor and operator-(int, int) // we can access m_cents directly because this is a friend function return Cents(c1.m_cents - c2.m_cents); } int main() { Cents cents1{ 6 }; Cents cents2{ 2 }; Cents centsSum{ cents1 - cents2 }; std::cout << "I have " << centsSum.getCents() << " cents.\n"; return 0; } |

Overloading the multiplication operator (*) and the division operator (/) is as easy as defining functions for operator* and operator/ respectively.

Friend functions can be defined inside the class

Even though friend functions are not members of the class, they can still be defined inside the class if desired:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
#include <iostream> class Cents { private: int m_cents; public: Cents(int cents) { m_cents = cents; } // add Cents + Cents using a friend function // This function is not considered a member of the class, even though the definition is inside the class friend Cents operator+(const Cents &c1, const Cents &c2) { // use the Cents constructor and operator+(int, int) // we can access m_cents directly because this is a friend function return Cents(c1.m_cents + c2.m_cents); } int getCents() const { return m_cents; } }; int main() { Cents cents1{ 6 }; Cents cents2{ 8 }; Cents centsSum{ cents1 + cents2 }; std::cout << "I have " << centsSum.getCents() << " cents.\n"; return 0; } |

We generally don’t recommend this, as non-trivial function definitions are better kept in a separate .cpp file, outside of the class definition. However, we will use this pattern in future tutorials to keep the examples concise.

Overloading operators for operands of different types

Often it is the case that you want your overloaded operators to work with operands that are different types. For example, if we have Cents(4), we may want to add the integer 6 to this to produce the result Cents(10).

When C++ evaluates the expression `x + y`

, x becomes the first parameter, and y becomes the second parameter. When x and y have the same type, it does not matter if you add x + y or y + x -- either way, the same version of operator+ gets called. However, when the operands have different types, x + y does not call the same function as y + x.

For example, `Cents(4) + 6`

would call operator+(Cents, int), and `6 + Cents(4)`

would call operator+(int, Cents). Consequently, whenever we overload binary operators for operands of different types, we actually need to write two functions -- one for each case. Here is an example of that:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
#include <iostream> class Cents { private: int m_cents; public: Cents(int cents) { m_cents = cents; } // add Cents + int using a friend function friend Cents operator+(const Cents &c1, int value); // add int + Cents using a friend function friend Cents operator+(int value, const Cents &c1); int getCents() const { return m_cents; } }; // note: this function is not a member function! Cents operator+(const Cents &c1, int value) { // use the Cents constructor and operator+(int, int) // we can access m_cents directly because this is a friend function return { c1.m_cents + value }; } // note: this function is not a member function! Cents operator+(int value, const Cents &c1) { // use the Cents constructor and operator+(int, int) // we can access m_cents directly because this is a friend function return { c1.m_cents + value }; } int main() { Cents c1{ Cents{ 4 } + 6 }; Cents c2{ 6 + Cents{ 4 } }; std::cout << "I have " << c1.getCents() << " cents.\n"; std::cout << "I have " << c2.getCents() << " cents.\n"; return 0; } |

Note that both overloaded functions have the same implementation -- that’s because they do the same thing, they just take their parameters in a different order.

Another example

Let’s take a look at another example:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
#include <iostream> class MinMax { private: int m_min; // The min value seen so far int m_max; // The max value seen so far public: MinMax(int min, int max) { m_min = min; m_max = max; } int getMin() const { return m_min; } int getMax() const { return m_max; } friend MinMax operator+(const MinMax &m1, const MinMax &m2); friend MinMax operator+(const MinMax &m, int value); friend MinMax operator+(int value, const MinMax &m); }; MinMax operator+(const MinMax &m1, const MinMax &m2) { // Get the minimum value seen in m1 and m2 int min{ m1.m_min < m2.m_min ? m1.m_min : m2.m_min }; // Get the maximum value seen in m1 and m2 int max{ m1.m_max > m2.m_max ? m1.m_max : m2.m_max }; return { min, max }; } MinMax operator+(const MinMax &m, int value) { // Get the minimum value seen in m and value int min{ m.m_min < value ? m.m_min : value }; // Get the maximum value seen in m and value int max{ m.m_max > value ? m.m_max : value }; return { min, max }; } MinMax operator+(int value, const MinMax &m) { // call operator+(MinMax, int) return { m + value }; } int main() { MinMax m1{ 10, 15 }; MinMax m2{ 8, 11 }; MinMax m3{ 3, 12 }; MinMax mFinal{ m1 + m2 + 5 + 8 + m3 + 16 }; std::cout << "Result: (" << mFinal.getMin() << ", " << mFinal.getMax() << ")\n"; return 0; } |

The MinMax class keeps track of the minimum and maximum values that it has seen so far. We have overloaded the + operator 3 times, so that we can add two MinMax objects together, or add integers to MinMax objects.

This example produces the result:

Result: (3, 16)

which you will note is the minimum and maximum values that we added to mFinal.

Let’s talk a little bit more about how “MinMax mFinal = m1 + m2 + 5 + 8 + m3 + 16” evaluates. Remember that operator+ has higher precedence than operator=, and operator+ evaluates from left to right, so m1 + m2 evaluate first. This becomes a call to operator+(m1, m2), which produces the return value MinMax(8, 15). Then MinMax(8, 15) + 5 evaluates next. This becomes a call to operator+(MinMax(8, 15), 5), which produces return value MinMax(5, 15). Then MinMax(5, 15) + 8 evaluates in the same way to produce MinMax(5, 15). Then MinMax(5, 15) + m3 evaluates to produce MinMax(3, 15). And finally, MinMax(3, 15) + 16 evaluates to MinMax(3, 16). This final result is then assigned to mFinal.

In other words, this expression evaluates as “MinMax mFinal = (((((m1 + m2) + 5) + 8) + m3) + 16)”, with each successive operation returning a MinMax object that becomes the left-hand operand for the following operator.

Implementing operators using other operators

In the above example, note that we defined operator+(int, MinMax) by calling operator+(MinMax, int) (which produces the same result). This allows us to reduce the implementation of operator+(int, MinMax) to a single line, making our code easier to maintain by minimizing redundancy and making the function simpler to understand.

It is often possible to define overloaded operators by calling other overloaded operators. You should do so if and when doing so produces simpler code. In cases where the implementation is trivial (e.g. a single line) it’s often not worth doing this, as the added indirection of an additional function call is more complicated than just implementing the function directly.

Quiz time

Question #1

a) Write a class named Fraction that has a integer numerator and denominator member. Write a print() function that prints out the fraction.

The following code should compile:

1 2 3 4 5 6 7 8 9 10 11 12 |
#include <iostream> int main() { Fraction f1{ 1, 4 }; f1.print(); Fraction f2{ 1, 2 }; f2.print(); return 0; } |

This should print:

1/4 1/2

b) Add overloaded multiplication operators to handle multiplication between a Fraction and integer, and between two Fractions. Use the friend function method.

Hint: To multiply two fractions, first multiply the two numerators together, and then multiply the two denominators together. To multiply a fraction and an integer, multiply the numerator of the fraction by the integer and leave the denominator alone.

The following code should compile:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#include <iostream> int main() { Fraction f1{2, 5}; f1.print(); Fraction f2{3, 8}; f2.print(); Fraction f3{ f1 * f2 }; f3.print(); Fraction f4{ f1 * 2 }; f4.print(); Fraction f5{ 2 * f2 }; f5.print(); Fraction f6{ Fraction{1, 2} * Fraction{2, 3} * Fraction{3, 4} }; f6.print(); return 0; } |

This should print:

2/5 3/8 6/40 4/5 6/8 6/24

c) Why does the program continue to work correctly if we remove the operators for integer multiplication from the previous solution?

1 2 3 |
// We can remove these operators, and the program continues to work Fraction operator*(const Fraction &f1, int value); Fraction operator*(int value, const Fraction &f1); |

d) If we remove the `const`

from the `Fraction * Fraction`

operator, the following line from the `main`

function no longer works. Why?

1 2 3 4 5 |
// The non-const multiplication operator looks like this Fraction operator*(Fraction &f1, Fraction &f2) // This doesn't work anymore Fraction f6{ Fraction{1, 2} * Fraction{2, 3} * Fraction{3, 4} }; |

e) Extra credit: the fraction 2/4 is the same as 1/2, but 2/4 is not reduced to the lowest terms. We can reduce any given fraction to lowest terms by finding the greatest common divisor (GCD) between the numerator and denominator, and then dividing both the numerator and denominator by the GCD.

The following is a function to find the GCD:

1 2 3 |
int gcd(int a, int b) { return (b == 0) ? (a > 0 ? a : -a) : gcd(b, a % b); } |

Add this function to your class, and write a member function named reduce() that reduces your fraction. Make sure all fractions are properly reduced.

The following should compile:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
#include <iostream> int main() { Fraction f1{2, 5}; f1.print(); Fraction f2{3, 8}; f2.print(); Fraction f3{ f1 * f2 }; f3.print(); Fraction f4{ f1 * 2 }; f4.print(); Fraction f5{ 2 * f2 }; f5.print(); Fraction f6{ Fraction{1, 2} * Fraction{2, 3} * Fraction{3, 4} }; f6.print(); Fraction f7{0, 6}; f7.print(); return 0; } |

And produce the result:

2/5 3/8 3/20 4/5 3/4 1/4 0/6

9.2a -- Overloading operators using normal functions |

Index |

9.1 -- Introduction to operator overloading |

I am really apprehensive about using recursive functions like on the example:

I assume this would lead into a stack overflow if I had comically large numbers (and a data type that could hold them) since everytime it recurses, it stores the return address into the stack. Is this worry of mine valid or am I just being paranoid?

Iirc that's the standard Euclid's algorithm for computing CGD, which has roughly O(log N) time complexity, so it shouldn't exhaust the stack memory even with large values (i.e. it'll quickly approach the base case).

I completed exercise 1b with just one friend operator overload for two fractions, I'm assuming it worked because on my Fraction class' constructor I had a default value for the denominator argument, which was 1. So it actually promoted (I hope that's correct termology) the integers into fractions with denominator 1.

My constructor:

I assume 2 got thrown into my constructor as some sort of promotion attempt by the compiler:

That's correct ("Promotion" is used for integer promotion, what's happening here is conversion). This is a common question, so I added 2 quiz questions (c and d).

Another good lesson, My solution was different than the original for question 1c). One thing to note I keep getting incomplete type error but code works fine. It may be an issue with visual studios. Go ahead and have a look:

No incomplete types here, looks good.

This lesson was using bad practices (std::endl, strings for characters, direct initialization). Have a look at the updated solution to see where you could've used list initialization.

Hi,

In the last example, the program would produce the same result without lines 19 and 44 to 48.

Not sure why they are there?

Thanks,

Without that overload, a temporary `MinMax` will be created every time you use `int + MinMax`. The `int` will be used to construct a `MinMax` and then the `MinMax + MinMax` overload is used. That's wasteful.

So, overloading functions and operators are the same about the syntax (the return type, parameter, implementation statements) but there 1 thing I still didn't really understand. It's the way we call an operator. Why we write "Cents operator +(Cents a, Cents b)" like this when we define the operator, but then we can call the operator by using "Cents a + Cents b", and not having to write "+(c1, c2)" like when we call a function, and the compiler still understands and works as expected ????

Operators have special rules, which permit this syntax. These rules aren't something that you can do in code, they're dictated in the standard and the compiler has to have special handling built in.

Is there a reason as to why you're including the reduce and gcd functions in the "public" part of the class in the last question? I'd assume that since we want the class to call the reduce function by default you'd avoid putting it in the user interface as it results in an option that user can't utilise in any way (since it's already been used) being displayed after the '.' operator when calling objects of that class.

https://stackoverflow.com/questions/4421706/operator-overloading-in-c/4421719#4421719

I wanted to pitch you this link a friendly person directed me to recently. What I found the most interesting:

_Arithmetic operators_: when providing operator+ one should also provide operator+=. If one provides it anyways one can use it to spare the friend declaration of operator+ and make its definition an ideom: copy one of the operands, add the other to it and return the result by value

This calls the same amount of constructors as doing operator+ the regular way but it ensures that we set the data of the temporary to the most effective init (namely the first summand).

https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom

_Copy swap_: It is in general a good idea to provide an overload of swap for classes that are intended to have multiple instances, because swap is often way cheaper than assign. Why not also make operator= an ideom :

this shows quite well by what assign is more expensive than swap: a copy.

I would like to know whether both these would allow to simply use std::move on the argument that is copied to make them cheaper if we don't need it anymore or whether we need to implement something (**) to make that possible. Point is: that would be very easy.

(**) is this:

the necessary part?

EDIT:

is what they say needs to be done for a move constructor. They also say we only need to add that move constructor, move assignment works with the same function.

1) Hi.In above you wrote"note: this function is not a member function!". Because operator+ is a friend function and friend function cant be member function. İsn't it?(but in lesson 8.13 we learned member function can be friend)

2)I get this error in line A:

Programming/cpp/learncpp/operator_overloading/main.cpp:22: error: undefined reference to `A::functionA(A)'

Why could it be?

3)Why you use const here?

1) There is no friend function in your example. `functionA` is a member function, just defined outside of the class (Assuming you fix (2)).

2) This error means that you declared something, but never defined it. `functionA` has nothing to do with `A::functionA`, `functionA` is a function of its own.

Hi,

I don't have an overloading function matching operands in line 21. Nevertheless, It's working! .I noticed when constructor has default values, and my overloading function has the arguments as 'const' it works (line 21), but when removing 'const' it stop working !! .

Hi

> I don't have an overloading function matching operands in line 21. Nevertheless, It's working!

`6` is used to construct a new `Student`, then `operator+(const Student&, const Student&)` is used. This works, but it's slower than providing a specialized `operator+` for integers.

> when removing 'const' it stop working

The `Student` constructed from `6` is a temporary. Non-const references can't bind to temporaries.

thank you a lot

Does operator overloading add to the stack?

There's nothing different compared to other functions.

If a class is const, does that affect how the plus operator is overloaded?

Classes can't be `const`. Can you provide an example of what you mean?

I mean making a class variable constant as talked about in Lesson 8.10.

No, it doesn't affect the plus operator. The plus operator doesn't modify any members, so it has no problem with `const`.

Does the operator symbol '+' in identifier "operator+" signify that it's an operator overload? Is that how compiler is able to differentiate between "operator+()" from a normal function identifier "operator()"?

> Does the operator symbol '+' in identifier "operator+" signify that it's an operator overload?

Yes

> Is that how compiler is able to differentiate between "operator+()" from a normal function identifier "operator()"?

Not sure I understand what you're asking. operator() doesn't mean anything syntactically.

https://en.cppreference.com/w/cpp/keyword/operator

"operator" is a C++ keyword, which means that you cannot define a function operator() anywhere. The only (current) usage of this keyword is with operator overloading.

If you tried to implement a function called operator that takes some values, eg via

the compiler will see that something is wrong syntactically since the keyword "operator" is followed by something that is not an operator and then complain about a missing type specifier.

If you tried to define function that doesn't take arguments, eg via

the compiler would try to interpret it as an implementation of operator() which is a unary operator. After seeing that you didn't give an operand for the unary operator it complains that you didn't define operator() correctly.

Side remark: One calls a class X for which there exists a definition of operator(), eg. via

a functor, since it can then be called like a function:

EDIT: lesson 9.4 tells us that operator() can only be defined as a member function, so the above is slightly wrong. This is one additional reason why you can't define a function named operator.

I was having some trouble with question 1b, and after playing around a bit I figured out that I was seeing a compile error because I forgot to mark the parameters as const. I had:

And it was causing this line to fail:

Eventually I found the reasoning at the top of this lesson: https://www.learncpp.com/cpp-tutorial/6-11a-references-and-const/

Since "Fraction{ 1, 2 }" is an r-value, it can't be the argument that initializes a non-const Fraction reference, f1. However, a const reference works.

I wanted to comment about this since the compiler error I got when I ran into this was not helpful (just said something about "unable to find override for operator*(Fraction, Fraction)") and it took quite a while before I understood the issue. I'd recommend that this point be covered explicitly, either in the lesson or in the solution for 1b. (e.g. "Remember to use const references to avoid copying. Also, if you forget your code won't work anyway in some cases because people will expect to be able to operator* 2 r-values but they can't")

This is a common mistake, I added comments to the solution.

One thing to consider here in the solution to quiz question 1c is whether or not we should really be placing a call to reduce() in the constructor. The implementation here almost seems like it could be an unexpected side-effect and really should be avoided. i.e. the programmer is now required to document the fact that any fraction that can be reduced will be reduced on construction and during any operation. Additionally, this class loses data as it can never store improper fractions. It may seem trivial, but new programmers should avoid unexpected side-effects like this if at all possible. Besides, if the programmer wants it reduced, it's as simple as another function call.

A legitimate viewpoint. On the other hand, requiring the programmer to remember to make extra calls to get something they might expect out of the box can also lead to errors.

I do agree that this behavior as implemented is not obvious (it requires the programmer to read the implementation). At the least, I added a note at the top of the class denoting this behavior. A better option might be to give the class a name that better describes it's function (e.g. ReducedFraction).

> Additionally, this class loses data as it can never store improper fractions

An improper fraction has a larger numerator than denominator -- those seem to work fine as far as I can tell. 5/2 gets stored as 5/2 and 6/2 gets stored as 3/1, which is properly reduced.

Why does this work

But this doesn't

Because there are 2 things called "gcd". The `int gcd` is the closest `gcd` (Closest scope) to that line, so it `gcd` resolves to the `int gcd`. You can't call an `int`, so you get an error. If you rename either of the `gcd`s, the code works.

Suggestion number 1

This was my first code. I tried to do it a bit differently, I did the division when multiplying. The program works, but it has a bug. If you create a dividable object, it will not divide it. So my suggestion is to add an 8th object. I corrected my code already, but someone may not see this point.

Question number 1

What is the difference here? Both codes seem to work fine. One has static, the other one doesn't.

Question number 2

Shouldn't this function have const? Cause if the function does not change the value it should always be const. Also at the start 2 examples of getCents() fucntion have a const and the third one does not. This may confuse some people.

> Question number 1

`static int gcd` has internal linkage, it can only be accessed by the file its defined in.

`int gcd` has external linkage, it can be accessed from the entire program (via a forward declaration).

This is covered in lesson 6.6 and 6.7.

> Question number 2

You're right! I added more `const` to the lesson.

For the 5'th example from the top, in the class "Cents" there is no + operator overload function that takes two integers as paramaters, but if in main I type, Cents c3 = 100 + 50;

there will be no error, and the value of 150 will be recorded to the private variable c3.m_cents. Even if I stated the following in main, Cents c4 = 20; it would still be recorded to c4.m_cents as a value of 20. How does the compiler know, that the value of 20 needs to be saved to m_cents, as there might be more than one int private member variable? The only thing that comes to mind is that Cents c4 = 20; calls a constructor function, and places 20 as paramter, so it would be the same as stating Cents c4(20);. Could you please elaborate on this? Thanks.

100 is an integer, 50 is an integer, you're doing integer + integer. The result is then converted to a Cents.

hello! So i've been trying to do exercise 1b but I can't get it to work. I've compared my code to the the sulllution and examples in this chapter and I can't spot what's wrong. I've also tried to search for the explenation on the internet but no luck getting it to work. the error i'm getting is 1>C:\Users\Nibar Ahmed\Google Drive\Documents\c++ practis\overLoadingArithmeticOperatorsFriendFunctionsQ1\overLoadingArithmeticOperatorsFriendFunctionsQ1\overLoadingArithmeticOperatorsFriendFunctionsQ1.cpp(37,22): error C2676: binary '*': 'Fraction' does not define this operator or a conversion to a type acceptable to the predefined operator. Here is the code.

You didn't overload any operators. You're never used `multiplyFraction` or `multiplyFractionInt`. Those functions should be called `operator*`.

Hi, Alex and Nascardriver!

Is a good idea to make gcd() and reduce() private? I think there is no any reason to use them publicly. So, if they are private member, then gcd() must be non-static method. But, what do you think?

I hope Alex would revise the solution number 1c, so this class works with cases: 0/0, n/0, 0/n, when n > 0. Because he said "Make sure all fractions are properly reduced", so, I think it should works with those cases.

My 2c:

* No on GCD, since it provides useful utility even if you don't have a Fraction object. There's no harm in letting the public use it, since it doesn't modify the object state.

* For reduce(), it depends on whether you think anybody will ever have a reason to call reduce() explicitly. They don't in the example, so in this use case, it could be made private.

Fractions with a zero denominator are invalid. As noted in a prior lesson, these examples typically omit error handling because error handling adds clutter to the concepts being taught.

I updated the example to handle 0 numerators though. Thanks for the suggestion.

Hi, Alex. Thanks for your thought! I appreciate that!

Hi, Alex and Nascardriver!

In this lesson, I just realize that we can do this

and it works fine! Interesting! Now, it's clear to me to think a class just a data type!

Hi, Alex and Nascardriver!

Do you prefer this?

or this

in our operator overloading, we're just take two arguments. Why I can do this?

In normal function, we cannot do this, right? Are there any explanations?

I'd prefer the getCents() version as a non-friend.

`Cents sumCents = cent1 + cent2 + cent2 + cent1;`

evaluates as`Cents sumCents = (((cent1 + cent2) + cent2) + cent1)`

With the result of each call to operator+ becoming the left hand operand of the next call to operator+.

You can do this with normal functions: See lesson 8.8 (the hidden this pointer), the example that contains

`calc.add(5).sub(3).mult(4);`