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." << std::endl; 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." << std::endl; return 0; } |

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

**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." << std::endl; 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 is not the same 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() { 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 Cents(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 Cents(c1.m_cents + value); } int main() { Cents c1 = Cents(4) + 6; Cents c2 = 6 + Cents(4); std::cout << "I have " << c1.getCents() << " cents." << std::endl; std::cout << "I have " << c2.getCents() << " cents." << std::endl; 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 |
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() { return m_min; } int getMax() { 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 MinMax(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 MinMax(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.

One other interesting thing to note is that we defined operator+(int, MinMax) by calling operator+(MinMax, int). This may be slightly less efficient than implementing it directly (due to the extra function call, assuming your compiler can’t optimize the function call away), but keeps our code shorter and easier to maintain because it reduces duplicate code. It is often possible to define overloaded operators by calling other overloaded operators -- when possible, do so!

**Quiz time**

1a) 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 |
#include <iostream> int main() { Fraction f1(1, 4); f1.print(); Fraction f2(1, 2); f2.print(); } |

This should print:

1/4 1/2

1b) 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 |
#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(); } |

This should print:

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

1c) 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 |
#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; } |

And produce the result:

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

9.2a -- Overloading operators using normal functions |

Index |

9.1 -- Introduction to operator overloading |

Hi Alex,

Happy New Year!

I understand that, when you overload an operator like in the example that you have given:

you must return by value, as the result goes out of scope. On the other hand, you often preach that passing or returning large objects by value is not performant.

I am tempted to write a class representing matrices. These surely can become large. What would be the proper way to overload the arithmic operators in such a case?

And by the way: I was looking for an answer to that question in the comments. I appreciate your patience in answering the people here.

Thanks in advance

Hi Benjamin, Happy New Year!

Your compiler will usually optimize return values to get rid of this problem.

In Chapter 15 (Move semantics and smart pointers) you’ll learn more about efficiently handling large objects.

Alex might be able to elaborate return value optimization.

I suggest returning it by value. The alternatives (return by reference/address or an out parameter) both have more serious downsides or fragility issues.

However, there are two things that can work in our favor here, both of which Nascardriver has already identifier:

1) A good optimizing compiler may be able to elide the copy, preventing an unnecessary copy from being made. I talk more about copy elision later in this chapter. Rather than re-explain it here, just keep reading. 🙂

2) If your class uses dynamically allocated memory, it would probably benefit from move semantics. This would allow the class data to be transfered rather than cloned, which is a lot less expensive (basically copying a pointer rather than the entire data). I talk about move semantics in chapter 15.

Is it acceptable to initialize the reduction protocol in the constructor?

e.g.

//codecodecode

Fraction(int num, int den) : m_num{ num/gcd(num, den) }, m_den{ den/gcd(num, den) }

{

assert(m_den != 0 && "denom was zero");

}

//codecodecode

It’s syntactically legal. But I don’t think I’d recommend doing so for two reasons:

1) It’s hard to read.

2) It calls gcd() twice when it could be called once otherwise.

Hi Alex,

Why do we need to write the name of the class after "return" while overloading the operator?

Also, why did u not do the same while calling the function having parameters of different types?

MinMax operator+(int value, const MinMax &m)

Good questions.

1) It’s better to be explicit than implicit when doing a conversion. Using Cents(c1.m_cents + c2.m_cents); makes it clear we’re intending to return a Cents object. Returning just c1.m_cents + c2.m_cents relies on an implicit conversion from int to Cents and leaves more room for interpretation or compiler errors.

2) There’s no conversion in this case. All we’re doing is calling the function above it (which returns a MinMax). Since this function returns a MinMax as well, we don’t need to specify that we want a MinMax (that’s redundant).

Why do you use parentheses in the second case instead of just

return m + value;

They’re extraneous, and I’ve removed them.

Hallo Alex,

I tried the solution the last quiz question without making the gcd function static. Here’s how I changed it:-

int gcd(int a, int b)

{

return (b == 0) ? (a > 0 ? a : -a) : gcd(b, a % b);

}

void reduce()

{

int gd = gcd(m_numerator, m_denominator);

m_numerator /= gd;

m_denominator /= gd;

}

And it worked. I have the following questions:-

1. Can member functions call other member functions without the object. Like reduce called gcd?

2. I also tried a variant where gcd was static, but I called it from reduce as follows:-

static int gcd(int a, int b)

{

return (b == 0) ? (a > 0 ? a : -a) : gcd(b, a % b);

}

void reduce()

{

int gd = gcd(m_numerator, m_denominator);

m_numerator /= gd;

m_denominator /= gd;

}

I didn’t need to scope resolve it as Fraction::gcd(m_numerator, m_denominator). Why did it work?

3. Why are we making gcd static? There is no need for it to be static? What was the motivation to make gcd static?

I’d appreciate the answers to my questions and thanks again for great tutorials!

1) No. When (non-static) member functions call other (non-static) member functions, the object is implicitly passed (via the hidden this parameter).

2) Functions inside the class can see other functions inside the class, so the scoping qualifier isn’t necessary.

3) We made it static so you can call Fraction::GCD without instantiating a Fraction object. e.g.

Hello,

I don’t understand two things of the first part of the lesson:

1- Why you declare overload operators Cents instead of int? and then you create a r-value which is more expensive, isn’t it?

2- Why you copy initialize the class doing

instead of doing direct initialization

Many thanks!.

1) Because in the example, we’re showing how to add two Cents objects together. Later on, we show how to add a Cents and an int (in either order). Where do I create an r-value? Not sure what that part is in reference to.

2) Stylistic choice. Either works, and the compiler will likely treat them the same.

Ok. Thank you. Regarding to point 2), I was asking because in earlier chapters I think you said something like "try to avoid copy initialization and use direct initialization". But maybe it was in a different context.

Thanks.

Generally it _is_ better to use direct initialization, as copy initialization can cause issues in certain cases (most often when the initializer and initialized are different types). In this case, it should be the same, but that’s not _always_ the case, hence the recommendation.

Hi, under the section "Friend functions can be defined inside the class", you say you do not recommend doing this for "non-trivial member function definitions". This is confusing, as a friend function is not a member function, I would recommend you re-write that.

Thanks for the suggestion. Fixed!

Experienced programmers may laugh at me but this function blew my mind. Never saw the conditional operator nested like that. The recursive function is the cherry on top. I hope I will someday envision equally clever scripts.

“Clever” is something that is usually best avoided in programming. 🙂 In this case, it’s marginally acceptable because the nested conditional is trivial (it’s just the absolute value of variable a).

[#include <iostream>

using namespace std;

class Fraction

{

private:

int num;

int den;

public:

Fraction(int m_num=0, int m_den=1)

{

num=m_num;

den=m_den;

}

friend Fraction operator*(Fraction &m1 , Fraction &m2);

friend Fraction operator*(Fraction &m , int m2);

friend Fraction operator*( int m1 , Fraction &m);

void print()

{

cout<<num<<"/"<<den<<endl;

}

};

Fraction operator*(Fraction &m1 , Fraction &m2)

{

return Fraction ((m1.num*m2.num),(m1.den*m2.den));

}

Fraction operator*(Fraction &m , int m2)

{

return Fraction ((m.num*m2),(m.den));

}

Fraction operator*( int m1 , Fraction &m)

{

return Fraction ((m1*m.num),(m.den));

}

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;

}

]

i’m getting an error "invalid operands to binary epression" for f6… why so ?

When Fraction(1,2) is multiplied by Fraction(2,3), the result is a new Fraction that is an r-value. This r-value gets multiplied by Fraction(3,4).

Your overloaded multiplication operator is using a non-const reference parameter. Non-const references can’t bind to l-rvalues. If you make your parameters const references, then they will be able to bind to r-values and you should be good to go.

Hello Alex,

I really liked your chapter on operator overloading -- especially compared to other introductions that I read before it’s starting more than slow enough. I agreed, the "friend method" is more readable as the reader can directly see the origins of input and output in the code. It’s so much easier to understand at the beginning if you don’t have to remind yourself that the other operand is accessed directly via the calling object… though I’ll be interested to see the benefits of that syntax soon 😉

However, I think the solution of quiz 1c) has an issue and some weird behavior:

causes

to crash, that might be the right place for an assert():

Try

and you’ll see that the constructor may change the sign of both numerator and denominator. The reason is "operator%()":

In the above case, we have the calls

Both numerator and denominator are divided by -1 and change signs! You can solve this issue if you force gcd() to return the absolute value:

-----------

P.S.: In maths they do exactly the same thing -- all operators used can have different meanings depending on the fields/spaces/… where they are defined. E.g. on the real numbers, "+" simply adds two numbers, whereas on finite real vector spaces, "+" is defined to add the vectors’ components. As the components are real numbers, vector addition is well defined and reuses the "+" for real numbers.

From a programmers point of view, in maths all those fields/spaces/… which reuse (arithmetic) operators are really just classes that overload those (arithmetic) operators…

Sorry for the long post, I just realized that similarity between maths and programming and think it’s amazing just how similar the underlying concepts really are!

Yes, you’ll note that many of the examples don’t have proper error checking -- this is just to keep them simple. In this case, the Fraction constructor definitely should assert that m_denominator is not 0.

Thanks for the updated gcd() function. I’ve updated the example.

hello alex…

how can i make operator + function friend of two different class???i want to add two different objects of different class..

class A

{

int data_A;

public:

A(int x)

:data_A(x){}

int get_A()

{

return data_A;

}

};

class B

{

int data_B;

public:

B(int x)

:data_B(x){}

int get_B()

{

return data_B;

}

};

int main()

{

A a(5);

B b(7);

A sum=a+b; //is it possible?

B result =a+b; //is it possible?

}

Just add the function prototype as a friend inside each class and it will be friends to both.

Hi Alex,

First of all thanks for making this great tutorial. It has been very helpful in learning C++. On a side note, in the section “Overloading operators for operands of different types”

An inline function has been defined as:

int GetCents() { return m_cents; }

Shouldn’t it be getCents()? It has been called as getCents() from main().

Yep. Fixed. Thanks for pointing that out.

Hi Alex,

With only the friend function with two Cents parameters, my code still compiles and gives the correct result for the main function.

Can you tell me why this still works? I tried to debug and see what’s going on and seems like the integer(3) successfully converted to Cents type. Does this have to do with implicit conversion?

Yes. The Cents constructor is being used to implicitly convert integer 3 into a Cents(3), which can then be used as an operand for your overloaded operator+.

Dear Alex, as far as i can se the code i made is the same as the one given as the solution, save for the fact that it wont compile. More precisely the line in main where i state what f6 should be, gives me an error saying that ‘*’ cant act on arguments type Fraction Fraction (I’m using Xcode IDE, using GNU14++). So as far as i can understand this means that it doesn’t recognise my overloaded variant of ‘*’ operator. If i delete the last line in main, it executes just fine. Could you give me some insight as to what is happening?

Surprisingly, this compiles on Visual Studio.

The issue here is that you’re multiplying three anonymous fractions (which are r-values), but your overloaded operator* that multiplies fraction is taking non-const references (which can only bind to l-values). This should not be allowed.

You should change your operator* reference parameters to be const.

thank you for this explanation.

Hello Alex,

thank you for the great tutorial!!!

In the section "Another example" line 46, you should write "// call operator+(MinMax, int)".

Best regards!

Updated, thanks for the suggestion.

Hi Alex,

Can you please explain me why it s not allowed to return by reference ?

friend Test& operator+(const Test &obj1, const Test &obj2)

{

return Test(3);

}

You can only have a reference to an l-value. Test(3) is an r-value.

Beyond that, you should never return a reference to a locally defined variable, as the variable will be destroyed when the function ends and you will be left with a reference to garbage.

Thanks Alex 🙂

Typo in exercise 1b: "Hint: To multiply two fractions, fist multiply…"

Unless you mean to pound those fractions into submission. 😉

Hah! I do mean you should pound those fractions into submission. But I’ve fixed the typo regardless.

Take that, fractions!

hello Alex when i am trying compiling above code first one using friend function am getting an error like

{<Error 1 error C2661: ‘Cents::Cents’ : no overloaded function takes 2 arguments c:usersmanikanthdocumentsvisual studio 2013projectsthis1this1prct.cpp 20 1 this1

>

<]

[#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." << std::endl;

return 0;

}>]

The error message is complaining that there is no Cents constructor that takes two arguments. However, nowhere in your program is a Cents constructed with two arguments. Looks at the specific line the compiler is complaining about and see if you notice anything weird related to that.

[code]

static int gcd(int a, int b)

{

return b == 0 ? a : gcd(b, a % b);

}

[code]

This is a static member function.From article 8.12,we know that static member functions can only access static member variables.But here, it is working with local variables. So, i guess that static member functions can work on auto variables also.

Yes, static member functions can only access static member variables of the class they are associated with. But they can also access any other variables that are in scope, which could include function parameters, local variables, or global variables.

Hello, amazing tutorial, thank you! i have one question, when you put this line:

return Cents(c1.m_cents + c2.m_cents);

you are using the constructor again, but in 8.5 - Constructors, you put "They can not be explicity called" and to me seems like thats whats happend here. Can you help me please? i hope is not a dumm question .

This is actually a great question. Although it looks like we’re calling the Cents constructor directly, we’re actually not (it just looks like it). What we’re doing is creating an anonymous Cents object, which has the side-effect of calling the constructor. See lesson 8.14 -- Anonymous objects for more info on anonymous objects.

aaaa i get it now, thank you!!

Hello, Alex.

This may be a stupid question, but if I put the gcd function prototype inside the class:

and then outside the class I do this:

Visual Studio complains about "a storage class may not be specified here".

Also if I leave it without the Fraction::, the prototype complains and says it doesn’t find the function declaration. Could you explain this behavior? I find it confusing.

(The code works leaving static only in the prototype, and the declaration with Fraction::)

Thanks! 🙂

I’m can’t find any particular reason why C++ disallows you from redeclaring that the member function is static when you define the function outside the class.

One theory is that you only need to define the elements of the function prototype that are used to determine whether the function is overloaded. Static is not one of those things, since you can’t have a static and non-static version of a function that is otherwise identical.

Uhm, ok, thanks!

Why are we passing the arguments as const and by reference in the following:

MinMax operator+(const MinMax &m1, const MinMax &m2)

You should always pass objects that are classes by reference, to avoid making a copy. Const references allow you to pass in const objects, as well as anonymous objects (and literals, if that’s relevant).

public:

Fraction(int numerator, int denominator=1):

m_numerator(numerator), m_denominator(denominator)

{

// We put reduce() in the constructor to ensure any fractions we make get reduced!

// Since all of the overloaded operators create new Fractions, we can guarantee this will get called here

reduce();

}

// We’ll make gcd static so that it can be part of class Fraction without requiring an object of type Fraction to use

static int gcd(int a, int b)

{

return b == 0 ? a : gcd(b, a % b);

}

void reduce()

{

int gcd = Fraction::gcd(m_numerator, m_denominator);

m_numerator /= gcd;

m_denominator /= gcd;

}

in the snippet above from solution 1c , constructor is able to make a successful function call to reduce() even without knowing it’s prototype.

i wonder how’s the function call possible when the caller(constructor in this case) is unaware of the prototype of the function to be called as reduce() has not been forward declared here and defined below the calling constructor’s definition.

Classes work differently than global functions, in that the members of a class can be declared in any order. It’s one area where C++ definitely made tangible improvements.

Hi Alex, I have a doubt in the example of Overloading operators for operands of different types.

In the definition of second operator+(), shouldn’t it be

instead of

?

Both of these overloaded operators are calling the Cents(int) constructor, not calling overloaded operator+. It doesn’t matter whether you add value+c1.m_cents, or c1.m_cents+value -- either way you get an integer result that’s sent as the argument to the Cents constructor.

class Fraction

{

private:

int m_numerator = 0; --->why not invalid ?????????

int m_denominator = 1; --->why not invalid ?????????

public:

Fraction(int numerator, int denominator=1):

m_numerator(numerator), m_denominator(denominator)

{

}

void print()

{

std::cout << m_numerator << "/" << m_denominator << "\n";

}

};

initializing a class member in class template suppose to be invalid but its not i don’t get it ??????????

See lesson 8.5b -- Non-static member initialization. This ability was added in C++11.

I don’t know why, but every time I try to declare/define classes in separate header/source files and then use the functions in main(), it says "undefined reference to Class::Function()", even though I included the header files needed to use said classes/functions.

Are you instantiating class objects or trying to call the function directly via Class::Function? Only static functions can be called directly via Class::Function. Non-static functions have to be called through an instantiated object (e.g. Class x; x.function(); ).