5

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?

OJFord
  • 10,522
  • 8
  • 64
  • 98
tanz
  • 627
  • 1
  • 10
  • 21
  • 3
    You can write `std::cout << d;` instead of `d.print(std::cout)`. (You may substitute `std::cout` with another output stream such as a file). – crayzeewulf Jan 09 '15 at 23:45
  • I think your question is good, but the title is a bit misleading. How about "Why and how to overload operator<< for printing"? – jogojapan Jan 09 '15 at 23:52
  • I have changed the question. – tanz Jan 10 '15 at 00:00
  • Re: question 2, yes, do it! Yet another place where it will "just work" because you did it right is logging. Using an example from one popular logger, LOG4CPLUS_DEBUG(m_logger, "stack has " << stack); – Kenny Ostrom Jan 10 '15 at 00:43
  • @KennyOstrom have absolutely no idea how `"stack has " << stack` works. `"stack has "` is a C-style string literal, not an `std::ostream` – vsoftco Jan 10 '15 at 01:12
  • Some loggers work like a stream. That is one such case. It's a macro. A logger stores text often used for debugging or tech support purposes. – Kenny Ostrom Jan 10 '15 at 04:12

4 Answers4

6

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;
Barry
  • 286,269
  • 29
  • 621
  • 977
  • I think the main advantage of having a separate `display()` function that is invoked in `operator<<` is the possibility of using `operator<<` everywhere along a class hierarchy, writing it only once in the base class and marking the `display()` function `virtual`, correct me if I'm wrong. – vsoftco Jan 10 '15 at 00:50
  • @vsoftco I don't really see the difference in writing `void Derived::display(std::ostream&)` and `std::ostream& operator<<(std::ostream&, Derived const&)`. Either way, the derived class needs its own method? – Barry Jan 10 '15 at 00:54
  • yes, indeed, however for "stylistic" reasons you may want to use only `operator<<` in displaying the content, and avoid re-defining it. Furthermore, this allows some classes along the hierarchy to not override the `display()` function, so I think overall the solution is a bit more elegant. In fact, the derived classes may not choose to override the `display()` at all, and this approach will work. Otherwise, you would still need to define `operator<<` in every class along the hierarchy. – vsoftco Jan 10 '15 at 00:56
  • @vsoftco Derived classes could use the base's `operator<<` too, if they don't want to override it. – Barry Jan 10 '15 at 00:59
  • Just realized that I was thinking of a `friend` (or global) implementation of `operator<<`, since in general you don't want to make `operator<<` a member function. How would you do it without explicitly re-defining `operator<<` in the `Derived` class? – vsoftco Jan 10 '15 at 01:03
  • Thanks, indeed you're right. I guess then the only advantage of using a virtual member function is the fact that it can be hidden from the user, by making it protected, cannot see any other advantage. – vsoftco Jan 10 '15 at 16:02
  • why we have friend identifier here? – tanz Jan 11 '15 at 02:25
6

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.

OJFord
  • 10,522
  • 8
  • 64
  • 98
  • why we use friend identifier? – tanz Jan 11 '15 at 02:26
  • 1
    @tanz Declaring the function a `friend` allows the definition to use `private` members. Useful if it is to print out information that is otherwise not publicly accessible. (Usually the case). – OJFord Jan 11 '15 at 02:29
1

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.

ciremai
  • 29
  • 2
  • why we use friend identifier? – tanz Jan 11 '15 at 02:27
  • 1
    @tanz__Usually overloaded 'operator<<' function is a nonmember function eventhough you define the function prototype inside class. As you know, private data are accessible only to member function of a class. Since this overloaded function are nonmember function, we use 'friend' identifier to this function so that it will be able to access class private or protected data. – ciremai Jan 11 '15 at 19:02
0

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.

Community
  • 1
  • 1
vsoftco
  • 55,410
  • 12
  • 139
  • 252