Using std::ostream as argument to a print function

20,696

Solution 1

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.

Solution 2

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;
Share:
20,696
tanz
Author by

tanz

Updated on July 24, 2022

Comments

  • tanz
    tanz almost 2 years

    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();
    }