Search

9.3 — Overloading the I/O operators

For classes that have multiple member variables, printing each of the individual variables on the screen can get tiresome fast. For example, consider the following class:

If you wanted to print an instance of this class to the screen, you’d have to do something like this:

Of course, it makes more sense to do this as a reusable function. And in previous examples, you’ve seen us create print() functions that work like this:

While this is much better, it still has some downsides. Because print() is a normal member function, it can’t be called in the middle of an output statement. Instead, you have to do this:

It would be much easier if you could simply type:

and get the same result. No having to break up output across multiple statements, and no having to remember what you named the print function.

Fortunately, by overloading the << operator, you can!

Overloading operator<<

Overloading operator<< is similar to overloading operator+ (they are both binary operators), except that the parameter types are different.

Consider the expression std::cout << point. If the operator is <<, what are the operands? The left operand is the std::cout object, and the right operand is your Point class object. std::cout is actually an object of type std::ostream. Therefore, our overloaded function will look like this:

Implementation of operator<< for our Point class is fairly straightforward -- because C++ already knows how to output doubles using operator<<, and our members are all doubles, we can simply use operator<< to output the member variables of our Point. Here is the above Point class with the overloaded operator<<.

This is pretty straightforward -- note how similar our output line is to the line in the print() function we wrote previously. The most notable difference is that std::cout has become parameter out (which will be a reference to std::cout when the function is called).

The trickiest part here is the return type. With the arithmetic operators, we calculated and returned a single answer by value. However, in this case, we return the left hand parameter as a reference. We do this so we can “chain” output commands together, such as std::cout << point << std::endl;

Consider what would happen if our operator<< returned void. When the compiler evaluates std::cout << point << std::endl;, due to the precedence/associativity rules, it evaluates this expression as (std::cout << point) << std::endl;. std::cout << point calls our void-returning overloaded operator<< function, which returns void. Then the partially evaluated expression becomes: void << std::endl;, which makes no sense!

By returning the out parameter as the return type instead, (std::cout << point) returns std::cout. Then our partially evaluated expression becomes: std::cout << std::endl;, which then gets evaluated itself!

Any time we want our overloaded binary operators to be chainable in such a manner, the left operand should be returned (by reference). Returning the left-hand parameter by reference is okay in this case -- since the left-hand parameter was passed in by the calling function, it must still exist when the called function returns. Therefore, we don’t have to worry about referencing something that’s gone out of scope and been destroyed.

Just to prove it works, consider the following example, which uses the Point class with the overloaded operator<< we wrote above:

This produces the following result:

Point(2, 3.5, 4) Point(6, 7.5, 8)

Overloading operator>>

It is also possible to overload the input operator. This is done in a manner analogous to overloading the output operator. The key thing you need to know is that std::cin is an object of type std::istream. Here’s our Point class with an overloaded operator>>:

Here’s a sample program using both the overloaded operator<< and operator>>:

Assuming the user enters 3.0 4.5 7.26 as input, the program produces the following result:

You entered: Point(3, 4.5, 7.26)

Conclusion

Overloading operator<< and operator>> make it extremely easy to output your class to screen and accept user input from the console.

Quiz time

Take the Fraction class we wrote in the previous quiz (listed below) and add an overloaded operator<< and operator>> to it.

The following program should compile:

And produce the result:

Enter fraction 1: 2/3
Enter fraction 2: 3/8
2/3 * 3/8 is 1/4

Here’s the Fraction class:

Show Solution

9.4 -- Overloading operators using member functions
Index
9.2a -- Overloading operators using normal functions

102 comments to 9.3 — Overloading the I/O operators

  • Jason

    I understand everything on this page well enough to overload I/O operators. I feel I grasp everything that has been presented here.

    Still, I’m left wondering what goes on under the hood. For example:

    What does the & (reference operator) do here: ostream& operator< < I believe this is the first time I've seen anything like that, a reference to a function or something? Does this maybe somehow tie into function pointers?

    I'm in a little over my head at this point. I'm wondering if it's even important to know what's going on under the hood with this issue.

    Your thoughts?

    • Jason, ostream is a class provided as part of C++ that handles outputs streams. The details of how ostream is implemented is very complex, but fortunately also completely unnecessary to use it effectively.

      Since ostream is a class, ostream& is a reference to an ostream class. Note that we’re also taking an ostream& as a parameter. ostream is typically passed by reference because we don’t want to make a copy of it as we pass it around.

      So basically, our overloaded function takes an ostream as a parameter, writes stuff to it, and then returns the same ostream. This allows us to chain < < calls together:


      cout < < cPoint1 << cPoint2 << cPoint3;

      This resolves as follows:


      ((cout < < cPoint1) << cPoint2) << cPoint3;

      cout < < cPoint1 is resolved first, with cout becoming the ostream& parameter. When this overloaded function is finished writing to the out parameter, it returns that cout so the next call to < < can use it. Thus:


      ((cout < < cPoint1) << cPoint2) << cPoint3;

      becomes:


      (cout < < cPoint2) << cPoint3;

      becomes:


      cout < < cPoint3;

      This calls our overloaded function one last time. At the end of this function, cout is again returned. But there's nobody left to use it, so the return value is ignored. The expression ends, and the program moves to the next line.

    • Jason

      What really had me confused was the return by reference statement. This ostream& operator< < was confusing me simply because returning a value by reference is something I had not seen or done up until this point. It took me a little while to make sense of this. Anyway, here is some code that I came up with that helped me understand what takes place when returning a value by reference.

      • There really isn’t much difference between return statements and function parameters, except for the directionality of the data transfer and the fact that you can only have one return value.

        Pretty much everything you’ve learned about pass by value, reference, and address apply to return values in the same way that they apply to parameters.

  • Jason

    Hmm, can I reference my own classes in a manner similar to the way ostream& references an ostream class? If that is possible, could it be useful.

    Curiosity killed the cat! 🙂

    • Yes. This is typically done in two ways.

      Let’s say you wrote a class named Foo.

      If you are writing a function that lives outside of Foo:

      If writing a function that is a member of Foo:

      • Jason

        Then I shall in good time have to experiment coding a reference to a class. I imagine this will increase my understanding of the ostream implementation.

  • Tom

    Alex -

    I don’t understand why this:

    isn’t written like this:

    I guess I don’t get the difference between “out” and “cout”.

    ????

    Thanks.

    • Good question! Here’s what I think you might be missing: out might not be cout. It might be cerr (an output stream used for error conditions), or a file ostream object (an output stream for writing to a file instead of the screen). You’ll learn about both of these in the chapter on I/O. In those cases, we don’t want to write to cout, we want to write to whatever alternative output stream we’re using. Those alternative streams come into the overloaded < < operator as the "out" parameter. For example:
      cerr < < "You have hit error # " << nErrorNum << endl;

      This is broken up like this:


      ((cerr < < "You have hit error # ") << nErrorNum) << endl;

      cerr's overloaded extraction operator will receive cerr as the "out" parameter, and "You have hit error # " as a string parameter. When it is done loading the stream, it will return cerr. Then evaluation will continue, and we will have:


      (cerr < < nErrorNum) << endl;

      cerr's overloaded extraction operator will receive cerr as the "out" parameter, and nErrorNum as an integer parameter. When it is done putting the value of nErrorNum in the stream, it will return cerr again, and evaluation will continue:


      cerr < < endl;

      Again, cerr's overloaded extraction operator will receive cerr as the "out" parameter, and endl as it's other parameter. It will do it's thing, return cerr, and evaluation will continue. At this point, there's nothing left to evaluate, so evaluation is complete.

      If we had returned cout instead of out, then nErrorNum and endl would have been printed to cout instead of cerr!

  • George D

    Hi

    I also have a problem that I cannot understand. I tried to compile my code with GNU C++. Here is a part of my code:

    The header file

    The source:

    The compiler sends the following error message: “/home/demarcsek/dev/Kalaha3/src/KCompress.h:63: error: ‘std::ostream& Kalaha::KCompress::BitArray::operator<<(std::ostream&, const Kalaha::KCompress::BitArray&)’ must take exactly one argument”
    When I modified this function with only one argument as a const BitArray& and used cout as a default stream, the compiler wrote the following message: “/home/demarcsek/dev/Kalaha3/src/KCompress.h:63: error: ‘std::ostream& Kalaha::KCompress::BitArray::operator<<(std::ostream&, const Kalaha::KCompress::BitArray&)’ must take exactly two arguments”

    It’s funny…Can anybody help me?

    Thanks,
    George

    • Joris

      ostream& BitArray::operator<< ( ostream& _stream, const BitArray& _arr )
      { //implementation
      return _stream;
      }
      That’s wrong - it shouldn’t be member function of the Bitarray class. Instead, it should be a “global” function:

      Instead use this:

      ostream& operator<< ( ostream& _stream, const BitArray& _arr )
      { //implementation
      return _stream;
      }

  • rehab

    why it should be friend?

    • Benjamin

      If you implement it as a member, it will have to be a member of ‘ostream’, taking one ‘Point’ as parameter:

      In c++ we can’t reopen and extend the ostream-class, so we have to use a friend function.

      Think of it the other way:
      if you implemented it as a member of ‘Point’…

      … you could pass a ‘ostream’ to the ‘Point’ class through the ‘<<‘-operator:

      This compiles, but (in our case) it doesn’t make any sence.

      Hope this helped!

      [offtopic]in some languages (i.e. ruby) you can reopen and extend existing classes (i.e. ‘ostream’)[/offtopic]

  • RevWaldo

    In the above example - any many others like it on the web - the code is written thus:

    Meanwhile many other texts - including a C++ textbook I’m using - would write it as:

    I imagine the complier just ignores the difference in whitespace, but what’s up with that? The first version makes more sense to me, while the second makes me scratch my head. Can anyone clarify why they’d write it differently? Or are they actually different?

    • serenity

      This is purely a matter of style. Choose whichever you prefer, since as you guessed, the whitespace is ignored by the compiler.

      I don’t have a reason for it that I can explain, but I prefer “char *func()” and “char &func()” over “char* func()” and “char& func()”. I guess I was raised that way. 😉

  • the line cout<<date1+date2 outputs wrong result, i cannot find why..

  • RSA

    this should work now

    • Yes, it works, thanks for your solution. Furthermore, can you explain me why, thanks in advance:)

      • RSA

        This type of error is compiler specific. The reference of the newly created date is no longer valide when the function exits because all the data inside that function are all destroyed. There are few ways to solve this problem, for example you can make static your variable if you consider that its lifetime to be the whole execution of the program. You can make it global and assign with the new operator like I did, but you musn’t forget to delete all variables that used “new” (when the program ends the os deletes them automatically). Here it worked because pointer created with “new” remained in the memory. But you should make it global and delete it if you want to avoid memory leak during execution, or make it static.

        • Rahul

          Hi RSA,

          As per your explanation, how come default copy constructor manages to perform the similar kind of access which overloaded<< operator could not able to perform.

          • Alex

            The problem with the original program is that it was returning a local (anonymous) variable by reference. That means it was returning a reference to something going out of scope.

            RSA’s solution actually isn’t the best, because a developer wouldn’t expect operator+ to dynamically allocate a new instance of Date. A better thing to do would be this:

            That way, a copy of the date is returned by value.

  • saini

    would anyone help to understand me why are we passing both the arguments as a reference,and what will happen if we pass them as value parameters

    • Gammerz

      Alex replied to this above:-

      Since ostream is a class, ostream& is a reference to an ostream class. Note that we’re also taking an ostream& as a parameter. ostream is typically passed by reference because we don’t want to make a copy of it as we pass it around.

  • Gammerz

    When the operator<< function becomes a friend of class Point, it allows us direct access to the member variables m_dX, m_dY and m_dZ. We could avoid making the operator<< a friend of the class Point and instead use member functions GetX(), GetY() and GetZ(), for improved encapsulation. Is this example purely to demonstrate the use of the "friend" command or are we saying this is a preferred method?

    • Alex

      Although it might seem like having the friend use access functions would increase encapsulation, I’d argue there’s likely to be little value to be found here (unless those access functions are non-trivial).

      Friends functions can’t friend themselves (and thus subvert a classes access controls) -- the class itself has to say that a function is a friend, and thereby grants the friend function the same access as members. Because of that, friend functions really should be considered part of the class, even though they aren’t member functions -- and if you update your class, you should update the friend functions too.

      Personally, I don’t have any qualms about having my friend functions have direct access to the internal members of the class they are friends of.

  • zynk

    ostream& operator<< (ostream &out, Point &cPoint)
    {
    // Since operator<< is a friend of the Point class, we can access
    // Point's members directly.
    out << "(" << cPoint.m_dX << ", " <<
    cPoint.m_dY << ", " <<
    cPoint.m_dZ << ")";
    return out;
    }

    Hey Alex
    we are returning a reference to the object 'out', which has local scope. Is it legal??

    • Alex

      Yes, it’s legal in this case because the return value was passed _in_ as a reference parameter. This is one of the few times where it’s generally okay to return a value by reference.

  • etam

    You should mention that “<>” are originally arithmetic bitwise shift operators. http://en.cppreference.com/w/cpp/language/operator_arithmetic

  • Monster

    Thanks alot for accepting me as a member in this great website.
    I am interested in learning C++ so much and this website is a great source to depend on in learning C++…..

  • Aston

    In checking the final example of the “Overloading <<" section, I ran into a peculiar output that I can't understand. I've had a look through the comments, but can't see anyone else mentioning it!

    cPoint1 and cPoint2 are fed doubles, and the constructor takes those doubles and stores them in private variables of type double. These are then fed through the overloaded << operator, and *should* be printed in their native double form, to my understanding… however when I run the complete program I get the following as output:

    (2, 3, 4) (6, 7, 8)

    I can't see any point in the code where the doubles should be collapsed to integers, can anyone help? I literally copy-pasted the last two codeblock examples from the section to play around with, and added the required include for iostream and the std namespace at the top.

    • Alex

      Visual Studio (at least) prints doubles that have no decimal values as integers by default.

      You can see this here:

      This prints 2, not 2.0.

  • nice meme

    friend ostream& operator<< (ostream &out, const Point &cPoint);

    what does ostream& mean?

    • Tony

      << is a binary operator that links a stream and whatever is output to it. Also, << chains. So when you overload << you want your function to return a reference to a stream. Hence ostream& is the type of your overloaded << function.

    • Alex

      It means the function is returning a reference to an object of type ostream.

  • Tony

    Thanks for this great, great website.

    I am trying to put 9.2 and 9.3 together: overload +, and overload <<. Each of them works by itself. But if I put them together

    my compiler (Mac OS X 10.8 clang++) complains

    <b>operators 9.3 b.cpp:137:7: error: invalid operands to binary expression
          ('ostream' (aka 'basic_ostream<char>') and 'Point')
            cout << cPoint1 + cPoint2;
            ~~~~ ^  ~~~~~~~~~~~~~~~~~
    </b>
    followed by many many errors against /usr/include/c++/4.2.1/ostream like this one:
    <b>
    /usr/include/c++/4.2.1/ostream:112:7: note: candidate function not viable: no
          known conversion from 'Point' to '__ostream_type &(*)(__ostream_type &)'
          for 1st argument
          operator<<(__ostream_type& (*__pf)(__ostream_type&))
    </b>

    Here's the code:

    • Tony

      (I know RSA answered this question above, but I'm not really getting the answer. The code I posted (without the line that doesn't compile) works fine (and follows the code in 9.1 for MinMax) so returning a Point seems to yield a value in the calling program that works fine for assignment to p2. Why doesn't it parse as of the right type for the overloaded <<?)

      • Alex

        Your operator+ returns an anonymous Point object, which you’re then trying to pass into operator<< by reference. C++ won't let you have non-const references to anonymous objects. In your overloaded operator+ and operator<<, make your Point parameters const.

  • Muhammad Wahaj Khan

    I am fall in love with this site….so helpful…solve my problem regarding the concepts of overloading…keep it up this good work…again thanks. 😀

  • john

    In the function declaration:

    friend ostream& operator<< (ostream &out, Point &cPoint);

    the out object is passed in by reference. But where in the code
    does the out object come from.

    thanx.

  • above program crashes after taking the character input(char*) in function operator >>, Why and how to get rid of it?

    • Alex

      A few things here:
      1) Your overloaded operator >> and << both need to return ope.
      2) I put your program in a debugger and it’s crashing on the line where it’s reading obj.m_char with the following error message: Unhandled exception at 0x01122B8B in ConsoleApplication1.exe: 0xC0000005: Access violation writing location 0x0112EB64. Consider what’s happening here: When var is created, you’re pointing m_char at a string literal. In the lesson on string literals, I mentioned that string literals can and often live in read-only memory. When your input function tries to input m_char, you’re trying to overwrite a string literal in read-only memory, so you’re getting a memory access violation.

      It’s a little weird to me that you’re declaring a variable with default values and then asking the user to overwrite them. Generally you’d want to do one or the other.

      That aside, a fix is easy: change m_char from type char* to type std::string. That way, std::string can dynamically manage the memory needed to hold the string for you. You’ll also need to update your ret_char() function:

  • Sachin

    Alex, you are an excellent teacher, thank for providing this useful site, thank you  very much  🙂

  • Quang

    Dear Alex!! I’m trying my best to learn C++, so please help me out:
    - Why do you use ostream instead of Point as the friend function’s type although the function itself take objects from both ostream and Point class? Is ostream somehow a priority?
    - Why do we need to make reference like this:  friend ostream& operator….
    Thank you so much !

    • Alex

      Having the operator return ostream allows us to “chain” multiple inputs together:

      If we didn’t return an ostream, then we’d have to print each of these separately, like this:

      We make ostream a reference to prevent C++ from making a copy of the ostream argument every time the operator is called, or when ostream is returned.

  • Kyle

    Alex,

    For the Point class I overloaded opeartor+ and operator- to add and subtract x, y, and z for each point.

    I have the overloaded operator<< in my program and it works correctly.  I tried to add two points in a cout call and got errors at compile saying invalid operands to binary expression for <<.  However if I add the points into a new point and then try to print it there is no issue.  I can’t see why I can’t do it as an anonymous variable since my overloaded + for point returns a Point and << knows how to deal with that.

    A little more of the error
    invalid operands to binary expression (‘ostream’ (aka ‘basic_ostream<char>’) and ‘Point’)

    • Alex

      I was able to compile and run this program successfully in Visual Studio 2015. Can you provide the entire error message that you are getting, including which line it is complaining about?

      • Kyle

        I’m on a Mac, but haven’t had any different behavior with the clang compiler before.
        Full code:

        First two errors:
        repro.cpp:62:12: error: invalid operands to binary expression (‘ostream’ (aka ‘basic_ostream<char>’) and ‘Point’)
                std::cout << point1 + point2 << ‘\n’;
                ~~~~~~~~~ ^  ~~~~~~~~~~~~~~~
        /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:179:20: note:
              candidate function not viable: no known conversion from ‘Point’ to ‘std::__1::basic_ostream<char>
              &(*)(std::__1::basic_ostream<char> &)’ for 1st argument
            basic_ostream& operator<<(basic_ostream& (*__pf)(basic_ostream&));
                           ^

        After that are a lot more notes about not being able to convert from Point to different types for the 1st argument.  It seems to think that the first argument to << is a Point (I’m guessing point2).  But that doesn’t make much sense because the operator precedence should complete point1 + point2 and return a Point, then << should happen left to right and my overloaded operator<< would then get the arguments with the ostream as the first argument.

        • Alex

          I think I see the problem here.

          If you look at your overloaded output operator:

          Note that Point is a non-const reference parameter.

          But when you call it:

          point1 + point2 is an rvalue and doesn’t have an address, so it can’t be passed to a non-const reference.

          The solution is easy: make your Point parameter const. That way it can take either an lvalue or an rvalue argument. You should be doing this anyway since your output operator doesn’t modify the Point parameter.

          • Kyle

            Thanks, that was it.  Now I see it, but the compiler was not very helpful here.  I can usually puzzle out the errors but wasn’t able to this time.  Thanks for the help.

  • Rahul

    Here, why I am not allowed to make any of these as constants.

  • Reaversword

    Ok, I have a question about.

    Playing with this, I’ve realized its possible the operator the user chooses to overload can "get confused to ostream".

    So I’ll be short this time. Two 3d points.

    point1(4,5,6)
    point2(1,2,3)

    1)We have ready an overload for ostream that show us the 3d point we send.
    2)We overload a sum of the points with "operator+".

    Its perfectly possible write:

    cout<<point1+point2<<endl;

    But if we change operator+ for, (for example), "|" or "^" in step 2, then it isn’t possible get this working:

    cout<<point1^point2<<endl;

    We then need to put it in this way:

    cout<<(point1^point2)<<endl;

    I guess is a matter of precendences, or maybe a special way ostream haves to interpret that operators.

    I’ve no idea why happens this, but I suspect the mystery will be revealed in I/O lesson (chapter 13).

    Anyway, if this points deserves a menction, I’m looking forward to know a little bit more now.

    • Alex

      It’s a matter of precedence.
      + has higher precedence than <<, so cout << point1 + point2 << endl; gets prioritized as cout << (point1 + point2) << endl; ^ has lower precedence than <<, so cout << point1 ^ point2 << endl; gets prioritized as (cout << point1) ^ (point2 << endl); That's why the explicit parenthesis are necessary in the second case.

  • Lokesh Nandan Meher

    "Any time we want our overloaded binary operators to be chainable in such a manner, the left operand should be returned."
    Is it a general rule to return the left operand or it  depends on associativity?

  • BlueTooth4269

    Apart from this lesson, the rule seems to be "use friend functions when the overloaded operator doesn’t modify the object".
    So why aren’t we making >> a member function?
    Still not entirely clear on when to use friend and when not to with operator overloading.
    Also - why does the >> function return an &istream? Can you chain the >> operator?

    Edit: Partially found the answer to my question: Binary operators can either be members of their left-hand argument’s class (because of the hidden *this pointer) or free functions. Since you can’t edit the ostream or istream objects (which in commonly used syntax are always on the left, and therefore the first parameter of the <> function), you have to use a free function, and to access the members it has to be a friend. Did I get all of that right?
    I still don’t understand why the binary arithmetic operators had to be friend functions though?

    • Alex

      Yes, you got it right. Binary arithmetic operators don’t have to be friend functions, but it’s easier to understand them if they are written that way.

      Also, yes, you can chain the >> operator.

  • Paul

    Just so I’m clear about the need for referencing the ostream and istream class, here’s how I think it works in very basic terms:

    1) I use ostream &operator<< to reference the ostream class so I can alter it to my liking.

    2) The first parameter ostream &out  -> references cout so I can alter it.

    3) The second parameter Point &cPoint  -> references the actual point from something like cout << cPoint so I can use it in the << definition

    4) After I define << to a particular format, I return out (the altered cout)

    5) Whenever I use << and an instance of type Point is on the right side, it will use this custom << definition

    6) When chaining is used, whatever is returned from the first function call to operator<< will become the new version of cout to use for the next data.
               So from cout << cPoint1 << cPoint2;  cout << cPoint1 becomes just cout, and we’ll be left with cout << cPoint2;

  • Annibale

    Would this code work?

    It can be a bit more memory consuming, but I think it would work as well and it should be possible to make multiple calls like

    Am I wrong?

    Thanks!

    • Alex

      That is exactly what the quiz solution does, except it passes and returns std::ostream by reference instead of by value for efficiency.

      Am I missing something?

  • Annibale

    Hi Alex,

           I was actually interested in the consequences of not using the reference symbol "&" while overloading the output operator. I was thinking it is just matter of efficiency, but I wanted to see it written. Thanks!

  • Rohan

    Hey Alex,
    The button to go to the next lesson points to lesson 9.6 instead of lesson 9.4
    This was a very helpful lesson!
    Thanks! Big fan of the site!

  • imranIQ

    #include <iostream>
    using namespace std;
    class DatA{
          int day,month,year;
          public:
                 DatA(int x = 0,int y = 0, int z= 0): day(x),month(y),year(z)
                 {
                 }
          friend iostream& operator<<(iostream &out,const DatA &obj);
                 };
          iostream& operator<<(iostream &out,const DatA &obj)
          {
                    out<<"Date is "<<obj.day<<"-"<<obj.month<<"-"<<obj.year<<endl;
                    return out;
                    }
          int main(){
              DatA Pakistan(4,17,2016);
              cout<<Pakistan<<endl;
              system("pause");
              }
    error :no match for "operator<<" in "std::cout<<Pakistan"

    when i try to compile this code system gives me mentioned error i tried my best but no mistake found . plz any can highlight the problem

  • SJ

    Hi Alex,

    Above in the lesson you have a line in both the operator<< and operator>> sections that say

    but they should be

  • Connor

    Hello again Alex.
    In the quiz why do we define, in reduce():

    I understand that gcd() is a static function but since reduce is being defined already within the class why can’t we drop the Fraction::

    It doesn’t throw an error - should it? Is it good practice to always define static members as such?

    • Alex

      will throw an error on some compilers, since some compilers get confused by the fact that there’s a local variable and static function by the same name. By using Fraction::gcd, we make it clear that the right hand side of the expression is a function call, not a reference to the variable we just defined.

  • Pip

    Alex, a minor detail in the quiz question of this section - a default parameter value appears to be missing in the constructor of the code supplied for the question (line 10):

    Compared to that given in the solution:

    I mention this because the former wouldn’t compile for me (but perhaps you included this as test of your readers).

  • Anddo

    OK this took time to process. Simply questions, I read almost all the answers which you explained well why the return by reference to the "out" object on the operator<< function. But what if I wanted to make it return by value !?. Once I do this

    VS 2015 gives me error on "return out;" being deleted function. I understand why we "should" work on this by passing by reference but I want to understand why it wont compile. The ostream is passed by reference so returning it by value shouldn’t be a problem, it’s not anonymous variable, is it ?

    • Anddo

      I searched a lot for this and made no sense to me until I found the answer. Returning by value is making a copy. Which leads the usage of copy constructor which is coming in the lesson "9.11 The copy constructor". Copy constructor of the all stream classes in C++ is disabled by having them made private.

      If I understood this incorrectly, please correct me.

    • Alex

      When you return a class by value, the compiler looks to see if there is a copy constructor to make the copy. It sounds like std::ostream has specified the copy constructor as “deleted” so that it can not be used in this way.

      We talk more about copy constructors at the end of this chapter.

  • Kattencrack Kledge

    In the quiz, on these codes:

    Is it good practice to write it like this:

    • Alex

      I’ve never seen anybody do it that way, though it seems like it would work.

      Personally, I like to keep my return statements as simple as possible, so there’s no ambiguity over what will be returned. In my version, it’s clear that operator<< returns out. In your version, it's not as obvious.

  • Danielo

    I was doing the fractions exercise, and it took me quite a lot of time to figure out why my program wasn’t working.

    It was because I wrote

    instead of

    I’m not sure why that const is important, I didn’t use const when I defined the operator (because I did some changes to the objects) and it works fine.

    It doesn’t seem logical to me why the object there has to be a const

    • Danielo

      oh, I just realized using const in the operator’s parameters like

      lets me chain objects, while doing the same without the const doesn’t let me.
      So, the consts are important. I still don’t get why

      • Alex

        Same reason. Your return value is being returned by value. If you try and chain it, it’s considered an anonymous object, and you can’t pass anonymous objects to non-const references.

    • Alex

      f1 * f2 is an anonymous object. You can’t pass anonymous objects to non-const references.

  • ash

    you said returning by reference allows us to chain. Can you explain or simulate what happens if we return by value the ostream object?

    ostream operator<< (ostream &out, Point &cPoint);

    • Alex

      The compiler won’t let you make a copy of std::ostream (std::ostream has declared its copy constructor as a deleted function -- we cover copy constructors later in this chapter). If you try, the compiler will give you a compile-time error.

  • Santosh Srinivas

    Your C++ tutorials are Wonderful. Thank you so much for your effort.
    I have read more than 3 books but couldn’t quite fully grasp the concept. But, your tutorials made it all a breeze with crystal clear and  simple explanations.
    Now the learning became fun.
    Thank you again.

  • Matt

    I had to backtrack a couple of sections in order to see why you decided to make gcd() a static function. I found that the reason for doing so was commented previously in the code, but not in the code in this section.

    Also, I had another question about this fraction class. I was wondering why you chose to give the member variables initial values, while also giving them default arguments in the constructor. Wouldn’t the default arguments have sufficed, or am I forgetting something?

    • Alex

      I added the comment to gcd() in this lesson so other users won’t have to backtrack. Thanks for noting that.

      The default arguments in the constructor suffice just fine. I’ve updated the example to remove the initializers.

  • Alexey Kolmyk

    Hello Alex! I have one question about overloading operator>>. Should we add some validation for user input? For example, for your class Point - add string check. Is it common practice to do validation in this case?

    • Alex

      It depends on what you mean by validation. Let’s take a sample use case of a failed input for the Point class.

      Consider the case where the user inputs: 3.0 q 5.0. 3.0 reads into m_x fine, but q is an invalid input. At this point, you can take any number of approaches:
      * Let std::cin fail the rest of the input and let the caller deal with it
      * Ask the user to try again
      * Throw an exception

      You’re also now in the case where m_x has been updated but m_y and m_z haven’t, which isn’t great.

      Personally, I don’t like having my operator>> do any kind of notification or re-prompting the user -- it’s an input operator, not an output operator. I think if I wanted to do validation of any kind, most likely I’d read the input into temp variables, update the class members only if all the input is valid, and otherwise use the std::cin fail states to communicate back to the caller that the input operation failed -- and leave it up to them to determine what to do about that. That way your Point isn’t left in an inconsistent state (half updated) and you’re not making any assumptions about what the caller wants to do about failed inputs.

  • Alexey Kolmyk

    Yes, I mean such kind of error and validation as you showed 🙂
    Thank you for your answer.

  • Rob G.

    Do I leave the constructor fields blank below on initialization? The operator will input those.

    • Alex

      You can if that’s what you desire.

      In this case, when point1 is created (with no parameters) it will use the default constructor, which will set m_x, m_y, and m_z to 0.0.

      Then you override those values with the user inputs.

  • Rob G.

    Hi Alex, built the function but don’t know why it works.

    I have 3 in statements that somehow know how to pick apart the numerator, the discard char x "/" and the denominator. I’ve confirmed each numerator and denominator are getting their correct numbers; both without the discard character. Whats going on here?

    • Alex

      If you’re typing in “1.0 2.0” for example, the discard character would be the space. If you’re typing “1.0/2.0” the discard character would be the ‘/’. But I’m just guessing -- what are you actually using as inputs?

  • Rob G.

    I’m typing an input for e.g.: “4/6”

  • Alex

    Hi, I used "in.ignore();" in the quiz instead when ignoring the "/" separator since it discards by default 1 character.

  • Best yet. Helped a lot. Thanks 🙂

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter