tanz
tanz

Reputation: 647

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?

Upvotes: 5

Views: 3419

Answers (4)

OJFord
OJFord

Reputation: 11140

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.

Upvotes: 6

ciremai
ciremai

Reputation: 29

Both display function are basically the same. The different is the way you call the function. With first function, you call function in usual way:

std::cout<<"This is MyStack (with first method): ";
m.display(std::cout);      //function call
std::cout<<std::endl;

With second function, you call function with operator "<<":

std::cout<<"This is MyStack (with second method): "
               <<m   //function call
               <<std::endl;

But I personally prefer the second one. Since it's more familiar to me.

Upvotes: 1

vsoftco
vsoftco

Reputation: 56567

As with regard to Question 2, this is the way to go if you have a base class and lots of derived classes, and want to write operator<< only once, in the base class. Then, if you declare the display() function as virtual along your class hierarchy, you can choose at runtime the correct display function. That is, if you have something like

Derived foo;
std::cout << foo;

then Base::operator<< will call the Derived::display(), because it is marked as virtual and foo is passed by reference. This is the way to go when you have a class hierarchy and don't want to overload operator<< for each derived class.

This is a common trick in avoiding code duplication. See

Making operator<< virtual?

on StackOverflow for more details.

Upvotes: 0

Barry
Barry

Reputation: 303457

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;

Upvotes: 6

Related Questions