Using std::ostream as argument to a print function
Asked Answered
P

2

9

I have always used cout to print the statement but now I want learn printing by passing the stream, something like void print(std::ostream&) const; my current print function looks like

template <class T>

void Mystack<T>::print()
{
    for (int i = 0; i <= top; i++)
    {
        std::cout << input[i] << " ";
    }
}

I have 2 questions:

  1. What is the benefit of switching from normal print function that I implemented above to the print function using ostream.
  2. How can I implement ostream in my function. I tried to understand ostream from internet source but could not understand. Please help.

Below is the complete running code:

//*************STACK CODE***************//

//VERY GOOD EXAMPLE TO UNDERSTAND RULE OF THREE FOR BEGINEERS http://www.drdobbs.com/c-made-easier-the-rule-of-three/184401400
//RULE OF THREE : Video : https://www.youtube.com/watch?v=F-7Rpt2D-zo
//Thumb Rule : Whenever we have class which has members pointing to heap space we should implement Rule of three.
//Concepts : Shallow Copy and Deep Copy

#include <iostream>
template <class T>
class Mystack
{
private:
    T *input;
    int top;
    int capacity;
public:
    Mystack();
    ~Mystack();
    void push(T const& x);
    void pop();
    T& topElement() const;
    bool isEmpty() const;
    void print();
};
template <class T>
Mystack<T>::Mystack()
{
    top = -1;
    capacity = 5;
    input = new T[capacity];
}
template <class T>
Mystack<T>::~Mystack() //Since we are using destructor explictly we need to apply Rule of 3
{
    delete [] input;
}
template <class T>
void Mystack<T>::push(T const& x)  //Passing x by Const Reference // Valus of x cannot be changed now in the function!
{
    if (top + 1 == capacity)
    {
        T *vec = new T[capacity * 2];
        for (int i = 0; i <= top; i++)
        {
            vec[i] = input[i];
        }
        delete []input; // Avoiding Memory Leak.
        input = vec;
        capacity *= capacity;
    }
    top++;
    std::cout << x;
    std::cout << &x;
    input[top] = x;
}
template <class T>
void Mystack<T>::pop()
{
    if (isEmpty())
    {
        throw std::out_of_range("Stack Underflow");
    }
    else
    {
        std::cout << "The popped element is" << input[top--];

    }
}
template <class T>
bool Mystack<T>::isEmpty() const
{
    if (top == -1)
    {
        std::cout << "Is Empty" << std::endl;
        return true;
    }
    else
    {
        std::cout << "Not Empty" << std::endl;
        return false;
    }
}
template <class T>
T& Mystack<T>::topElement() const
{
    if (top == -1)
    {
        throw std::out_of_range("No Element to Display");
    }
    else
    {
        std::cout << "The top element is : " << input[top];
        return input[top];
    }
}
template <class T>
void Mystack<T>::print()
{
    for (int i = 0; i <= top; i++)
    {
        std::cout << input[i] << " ";
    }
}
int main()
{
    Mystack<int> s1;
    Mystack<float> s2;
    Mystack<char> s3;
    int choice;
    int int_elem;
    float float_elem;
    char char_elem;
    std::cout << "Enter the type of stack" << std::endl;
    std::cout << "1. int ";
    std::cout << "2. float ";
    std::cout << "3. Char"<< std::endl;
    std::cin >> choice;
    if (choice == 1)
    {
        int  ch = 1;
        while (ch > 0)
        {
            std::cout << "\n1. Push ";
            std::cout << "2. Top ";
            std::cout << "3. IsEmpty ";
            std::cout << "4. Pop ";
            std::cout << "5. Exit ";
            std::cout << "6. Print"<<std::endl;
            std::cout << "Enter the choice" << std::endl;
            std::cin >> ch;
            switch (ch)
            {
            case 1:
                std::cout << "Enter the number to be pushed" << std::endl;
                std::cin >> int_elem;
                s1.push(int_elem);
                break;
            case 2:
                std::cout << "Get the TOP Element" << std::endl;
                try
                {
                    s1.topElement();
                }
                catch (std::out_of_range &oor)
                {
                    std::cerr << "Out of Range error:" << oor.what() << std::endl;
                }
                break;
            case 3:
                std::cout << "Check Empty" << std::endl;
                s1.isEmpty();
                break;
            case 4:
                std::cout << "POP the element" << std::endl;
                try
                {
                    s1.pop();
                }
                catch (const std::out_of_range &oor)
                {
                    std::cerr << "Out of Range error: " << oor.what() << '\n';
                }
                break;
            case 5:
                exit(0);
            case 6:
                s1.print();
                break;
            default:
                std::cout << "Enter a valid input";
                break;
            }
        }
    }
    else if (choice == 2)
    {
        int  ch = 1;
        while (ch > 0)
        {
            std::cout << "\n1. PUSH" << std::endl;
            std::cout << "2. TOP" << std::endl;
            std::cout << "3. IsEmpty" << std::endl;
            std::cout << "4. POP" << std::endl;
            std::cout << "5. EXIT" << std::endl;
            std::cout << "6. Print" << std::endl;
            std::cout << "Enter the choice" << std::endl;
            std::cin >> ch;
            switch (ch)
            {
            case 1:
                std::cout << "Enter the number to be pushed" << std::endl;
                std::cin >> float_elem;
                s2.push(float_elem);
                break;
            case 2:
                std::cout << "Get the TOP Element" << std::endl;
                try
                {
                    s2.topElement();
                }
                catch (std::out_of_range &oor)
                {
                    std::cerr << "Out of Range error:" << oor.what() << std::endl;
                }
                break;
            case 3:
                std::cout << "Check Empty" << std::endl;
                s2.isEmpty();
                break;
            case 4:
                std::cout << "POP the element" << std::endl;
                try
                {
                    s2.pop();
                }
                catch (const std::out_of_range &oor)
                {
                    std::cerr << "Out of Range error: " << oor.what() << '\n';
                }
                break;
            case 5:
                exit(0);
            case 6:
                s2.print();
                break;
            default:
                std::cout << "Enter a valid input";
                break;
            }
        }
    }
    else if (choice == 3)
    {
        int  ch = 1;
        while (ch > 0)
        {
            std::cout << "\n1. PUSH" << std::endl;
            std::cout << "2. TOP" << std::endl;
            std::cout << "3. IsEmpty" << std::endl;
            std::cout << "4. POP" << std::endl;
            std::cout << "5. EXIT" << std::endl;
            std::cout << "6. Print" << std::endl;
            std::cout << "Enter the choice" << std::endl;
            std::cin >> ch;
            switch (ch)
            {
            case 1:
                std::cout << "Enter the number to be pushed" << std::endl;
                std::cin >> char_elem;
                s3.push(char_elem);
                break;
            case 2:
                std::cout << "Get the TOP Element" << std::endl;
                try
                {
                    s3.topElement();
                }
                catch (std::out_of_range &oor)
                {
                    std::cerr << "Out of Range error:" << oor.what() << std::endl;
                }
                break;
            case 3:
                std::cout << "Check Empty" << std::endl;
                s3.isEmpty();
                break;
            case 4:
                std::cout << "POP the element" << std::endl;
                try
                {
                    s3.pop();
                }
                catch (const std::out_of_range &oor)
                {
                    std::cerr << "Out of Range error: " << oor.what() << '\n';
                }
                break;
            case 5:
                exit(0);
            case 6:
                s3.print();
                break;
            default:
                std::cout << "Enter a valid input";
                break;
            }
        }
    }
    else
        std::cout << "Invalid Choice";
    std::cin.get();
}
Philender answered 4/1, 2015 at 20:32 Comment(4)
std::cout is one particular std::ostream. There are others too, like output file streams. That is, taking an std::ostream reference parameter would allow you to print to a file and other things too. However, a print function is not usually the best way to do this. Instead, you should overload operator<< for std::ostream so that you can just do cout << my_stack;, for example.Hattiehatton
std::cout is an instance of std::ostream, so if your function accepts a parameter of that type, you can pass in std::cout including other instances of std::ostream like files, stringstreams, etc.Concerning
Unrelated, You may wish to make your stack Rule of Three - compliant in the not-too-distant future. You're currently missing a few pieces.Caricaria
@JosephMansfield A print function is useful if you want polymorphic behavior in stream inserters/extractors by making it virtual in a base class and having it be the delegate to those operators.Concerning
L
8

The benefit of switching to the ostream version is that in the case you later need to print to other places besides std::cout then you can do it with the same function implementation, whereas in this moment if you want to print to a file you would need to use a different function.

An example of how to implement it is instead of doing this:

void print()
{   
    std::cout << "Print something always to cout" << std::endl;
}

You do this (notice we are passing a reference):

void print(std::ostream& os) 
{   
    os << "Print something to wherever the caller wants to" << std::endl;
}   

Now instead of calling the function like:

print();

You will be calling the function like this to print to cout:

print(std::cout);

or like this to print to a file:

std::ofstream some_file("test.txt");
a.print(some_file);

See, with the same function you can decide where you want the print to go.

Lermontov answered 4/1, 2015 at 21:18 Comment(0)
T
3

Passing the stream as a parameter to the print function allows you to use the same print function with a different stream, for example you could use a std::stringstream and get the "output" as the content of a string instead of output to the console or a file. I recommend you create an overload for the "<<" operator, that way your code would look more natural/idiomatic in C++. I typically do this by defining a "friend" overload of "operator<<" in my class.

Here's an example of an operator<< overload, notice that because it is not a member function you also need to pass it the instance of the object you want to output, I pass it as a const reference to the object, you can also pass it by value:

    friend std::ostream & operator<<( std::ostream & o, const Mystack & stack ) {
        for (int i = 0; i <= stack.top; i++)
        {
            o << stack.input[i] << " ";
        }
        return o;
    }

This is what your class would look like with that function defined

template <class T>
class Mystack
{
private:
    T *input;
    int top;
    int capacity;
public:
    Mystack();
    ~Mystack();
    void push(T const& x);
    void pop();
    T& topElement() const;
    bool isEmpty() const;
    void print();
    friend std::ostream & operator<<( std::ostream & o, const Mystack & stack ) {
        for (int i = 0; i <= stack.top; i++)
        {
            o << stack.input[i] << " ";
        }
        return o;
    }
};

You would then use it like this

    case 6:
        std::cout << "The stack contents: " << s2 << std::endl;
        break;
Tasia answered 4/1, 2015 at 22:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.