Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why and how to overload operator<< for printing

I have written a program for implementation of stack. And I have one display function in it.

This is how I wrote display function at first:

template <class t>
void Mystack<t>::display()
{
    for (int i = 0; i <= top; i++)
    {
        std::cout << input[i] << " ";
    }
}

Then I was suggested by developers to write a display function to be more generic. So I wrote display function as:

template <class T>
void Mystack<T>::display(std::ostream &os) const         
{
    for (int i = 0; i <= top; i++)
    {
        os << input[i] << " ";
    }
}

As per my understanding the benefit of writing above function is that now I have a generic display function which I can use to display data to console or to a file too.

Question 1: Is my understanding correct?

Now another suggestion is to write function something like:

template <typename T>
friend std::ostream& operator<<(std::ostream& s, Mystack<T> const& d) {
    d.display(s);
    return s;
}

Question 2: What is the benefit of having above display function? What exactly will I be able to achieve by having above display function?

like image 657
tanz Avatar asked Jan 09 '15 23:01

tanz


2 Answers

For question 1, your understanding is correct, but the real improvement comes from question 2's suggestion of writing:

template <typename T>
friend std::ostream& operator<<(std::ostream&, Mystack<T> const& );

That will let anybody stream objects of your type in the same way they would stream anything else:

std::cout << "Hi, my stack is " << stack << ", it has size " << stack.size();

to any stream they want:

some_file << "Result of computation is: " << stack;
std::cerr << "Error, invalid stack: " << stack << ", expected: " << some_other_thing;
like image 126
Barry Avatar answered Sep 28 '22 02:09

Barry


Firstly - yes. By taking the std::ostream& parameter, you can output to any derived stream too, like std::ofstream, or std::cout, std::cerr.

Using operator<< allows you to, use that operator. Consider:

mystack<int> stackOfInts;
//...
std::cout << "Stack contents:" << std::endl << stackOfInts << std::endl;

It's just more idiomatic than a 'standard' function call.

Returning the stream allows the chaining of the operator, as in the above example. The chaining is effectively passing the result of a call to operator<< into another one:

operator<<( operator<<("Stack contents:", std::endl), stackOfInts ) );

If this overloaded call doesn't also return an std::ostream&, then there is no way to do:

operator<<( resultOfAbove, std::endl );

Declaring the function a friend allows its definition to use private members. Without this, you would have to do something like write a public getter for each private member.

like image 45
OJFord Avatar answered Sep 28 '22 02:09

OJFord