Using std::ostream as argument to a print function
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;
tanz
Updated on July 24, 2022Comments
-
tanz almost 2 years
I have always used
cout
to print the statement but now I want learn printing bypassing the stream
, something likevoid print(std::ostream&) const;
my current print function looks liketemplate <class T> void Mystack<T>::print() { for (int i = 0; i <= top; i++) { std::cout << input[i] << " "; } }
I have 2 questions:
- What is the benefit of switching from normal print function that I implemented above to the print function using
ostream
. - How can I implement
ostream
in my function. I tried to understandostream
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(); }
- What is the benefit of switching from normal print function that I implemented above to the print function using