Search

9.3 — Overloading the I/O operators

Overloading <<

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:

And that’s just for one instance! It would be much easier if you could simply type:

and get the same result. By overloading the << operator, you can! Overloading operator<< is similar to overloading operator+ (they are both binary operators), except that the parameter types are different. Consider the expression cout << cPoint. If the operator is <<, what are the operands? The left operand is the cout object, and the right operand is your Point class object. cout is actually an object of type ostream. Therefore, our overloaded function will look like this:

Implementation of operator<< 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 we wrote when we were outputting our members manually. They are almost identical, except cout has become parameter out! The only tricky part here is the return type. Why are we returning an object of type ostream? The answer is that we do this so we can "chain" output commands together, such as cout << cPoint << endl;

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

By returning the out parameter as the return type instead, (cout << cPoint) returns cout. Then our partially evaluated expression becomes: cout << 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.

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:

(2.0, 3.0, 4.0) (6.0, 7.0, 8.0)

Overloading >>

It is also possible to overload the input operator. This is done in a manner very analogous to overloading the output operator. The key thing you need to know is that cin is an object of type 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: (3, 4.5, 7.26)

Conclusion

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

Before we finish this lesson, there is one additional point that is important to make. The overloaded output operator<<

is actually better written as

This way, you will be able to output both const and non-const objects. However, for the overloaded input operator>>, you will have to leave cPoint as non-const because the overloaded operator>> modifies cPoints members.

By now, you should be starting to become comfortable with classes and passing parameters by reference. In future lessons, we will start making more of our parameters const references (which we should have been doing all along, but have abstained for purposes of simplicity). It is a good habit to get into early.

9.4 -- Overloading the comparison operators
Index
9.2 -- Overloading the arithmetic operators

42 comments to 9.3 — Overloading the I/O operators

  • yakisobskie

    Hi Alex! Great tutorial! btw Everything worked except for the operand>> tutorial. I'm getting an error "no match for operator>>...". I'm unable to understancd istream.

    How come there is no match for operand>>(istream, double) while
    operand<<(ostream, double) is working fine? Thanks!

    01| #include
    02| using namespace std;
    .
    .
    .

    34| istream& operator>> (istream& x, const Point& y)
    35| {
    36| x >> y.m_dX;
    37| x >> y.m_dY;
    38| x >> y.m_dZ;
    39| return x;
    40| }

    |36|error: no match for 'operator>>' (operand types are 'std::istream {aka std::basic_istream}' and 'const double')|

  • WONDERFUL TUTORIAL BY MR.ALEX..

    I REALLY UNDERSTAND....

  • 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++.....

  • etam

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

  • 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??

  • sw1983

    Nevermind I'd forgotten to use the namespace. haha, kick myself.

  • sw1983

    Hello, my compiler (visual c++ 2010) will not recognise ostream. It is saying it is an undeclared identifier. I've double checked and ostream is in the iostream library, I've included iostream. I thought it was something I was doing but I have copied and pasted Alex's code into my program and still I get the same error. What am I missing? I haven't written the function yet because the syntax gets underlined in red so I know it won't compile anyway.


    #include <iostream>
    #include <string>

    class Employee
    {
    private:
    static int sm_nID;
    int m_nID ;
    char m_strName[25];
    double m_dWage;

    public:
    Employee(char *strName="Blank", double dWage=10.00)
    {
    using namespace std;
    strncpy_s(m_strName, strName, 25);
    m_nID = ++sm_nID;
    m_dWage = dWage;
    }

    char* GetName()
    {
    return m_strName;
    }

    int GetID()
    {
    return m_nID;
    }

    double GetWage()
    {
    return m_dWage;
    }

    void Print()
    {
    using namespace std;
    cout << "Name: " << m_strName << "\t" << "Employee ID: " << m_nID << "\t" <<
    "Wage: " << m_dWage << "\n";
    }

    static void PrintID()
    {
    std::cout << sm_nID;
    }

    friend void ResetName(Employee &cEmployee);
    friend class FriendOfMine;
    /****************************HERE**************************************************/
    friend ostream& operator<< (ostream &out, Employee &cEmployee);
    };

    /****************************HERE**************************************************/

    ostream& operator<< (ostream &out, Employee &cEmployee)
    {

    }

    int Employee::sm_nID = 0;

    void ResetName(Employee &cEmployee)
    {
    strncpy(cEmployee.m_strName, "Reset", 25);
    }

    class FriendOfMine
    {
    public:
    void WageChange(Employee &cEmployee)
    {
    cEmployee.m_dWage = 5;
    }
    };

    int main()
    {

    return 0;
    }

  • rebelsoul

    Hello Alex,
    Thank you for such a good tutorial. I am facing a problem while running the above given code. I am using visual studio 2008, following your code and same input. However in result only the first input variable value is printed the rest are discarded.
    Here is a extract after debug.
    cPoint {m_dX=6.0000000000000000 m_dY=0.00000000000000000 m_dZ=0.00000000000000000

    Could you please guide, why the program is not taking all the value?

  • ARVIND

    While overloading output stream operator << as member member function I am getting following error:

    ostreamOprt.cpp:32: error: no match for 'operator<<' in 'std::cout << objs'
    /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/ostream.tcc:63: note: candidates are: std::basic_ostream& std::basic_ostream
    ::operator<<(std::basic_ostream&(*)(std::basic_ostream&)) [with _CharT = char, _Traits = std:
    :char_traits]
    /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/ostream.tcc:74: note: std::basic_ostream& std::basic_ostream::operator<<(std::basic_ios&(*)(std::basic_ios&)) [with _CharT = char, _Traits = std::char_traits]
    /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/ostream.tcc:86: note: std::basic_ostream& std::basic_ostream::operator<<(std::ios_base&(*)(std::ios_base&)) [with _CharT = char, _Traits = std::char_traits]
    /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/ostream.tcc:121: note: std::basic_ostream& std::basic_ostream::operator<<(long int) [with _CharT = char, _Traits = std::char_traits]
    /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/ostream.tcc:155: note: std::basic_ostream& std::basic_ostream::operator<<(long unsigned int) [with _CharT = char, _Traits = std::char_traits]
    /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/ostream.tcc:98: note: std::basic_ostream& std::basic_ostream::operator<<(bool) [with _CharT = char, _Traits = std::char_traits]
    /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/ostream:178: note: std::basic_ostream& std::basic_ostream::oper
    ator<<(short int) [with _CharT = char, _Traits = std::char_traits]
    /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/ostream:189: note: std::basic_ostream& std::basic_ostream::oper
    ator<<(short unsigned int) [with _CharT = char, _Traits = std::char_traits]
    /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/ostream:193: note: std::basic_ostream& std::basic_ostream::oper
    ator<<(int) [with _CharT = char, _Traits = std::char_traits]
    /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/ostream:204: note: std::basic_ostream& std::basic_ostream::oper
    ator<<(unsigned int) [with _CharT = char, _Traits = std::char_traits]
    /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/ostream.tcc:179: note: std::basic_ostream& std::basic_ostream::operator<<(long long int) [with _CharT = char, _Traits = std::char_traits]
    /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/ostream.tcc:214: note: std::basic_ostream& std::basic_ostream::operator<<(long long unsigned int) [with _CharT = char, _Traits = std::char_traits]
    /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/ostream.tcc:238: note: std::basic_ostream& std::basic_ostream::operator<<(double) [with _CharT = char, _Traits = std::char_traits]
    /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/ostream:219: note: std::basic_ostream& std::basic_ostream::oper
    ator<<(float) [with _CharT = char, _Traits = std::char_traits]
    /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/ostream.tcc:261: note: std::basic_ostream& std::basic_ostream::operator<<(long double) [with _CharT = char, _Traits = std::char_traits]
    /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/ostream.tcc:284: note: std::basic_ostream& std::basic_ostream::operator<<(const void*) [with _CharT = char, _Traits = std::char_traits]
    /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/ostream.tcc:307: note: std::basic_ostream& std::basic_ostream::operator<<(std::basic_streambuf*) [with _CharT = char, _Traits = std::char_traits]
    /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/ostream:449: note: std::basic_ostream& std::operator<<(std::basic_ostream&, char) [with _CharT = char, _Traits = std::char_traits]
    /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/ostream.tcc:505: note: std::basic_ostream& std::operator<<(std::basic_ostream
    &, char) [with _Traits = std::char_traits]
    /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/ostream:460: note: std::basic_ostream& std::operator<<(std::basic_ostream&, signed char) [with _Traits = std::char_traits]
    /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/ostream:465: note: std::basic_ostream& std::operator<<(std::basic_ostream&, unsigned char) [with _Traits = std::char_traits]
    /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/ostream.tcc:567: note: std::basic_ostream& std::operator<<(std::basic_ostre
    am&, const char*) [with _CharT = char, _Traits = std::char_traits]
    /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/ostream.tcc:612: note: std::basic_ostream& std::operator<<(std::basic_ostream
    &, const char*) [with _Traits = std::char_traits]
    /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/ostream:499: note: std::basic_ostream& std::operator<<(std::basic_ostream&, const signed char*) [with _Traits = std::char_traits]
    /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/ostream:504: note: std::basic_ostream& std::operator<<(std::basic_ostream&, const unsigned char*) [with _Traits = std::char_traits]

    Alex can you please explain why?

Leave a Reply

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">