Reputation: 51
I am attempting to overload the <<
operator to print out the private data of a BST (contains both a word and a count). I am required to make this operator a friend
non-member function of my WordTree
class, and cannot define any additional public
member functions (this is a school assignment).
Here is my operator<<
friend function:
ostream& operator<<(ostream &out, const WordTree& rhs)
{
out << InOrder(&out, rhs.root); // does not work as InOrder is private member function
return out;
}
And this is my private
function InOrder
that performs an in-order traversal on the BST.
ostream& WordTree::InOrder(ostream &out, WordNode* cur)
{
if (cur != nullptr)
{
InOrder(out, cur->m_left);
out << cur->m_data << " " << cur->m_count << endl;
InOrder(out, cur->m_right);
}
return out;
}
What are some ways I can approach this problem?
Upvotes: 0
Views: 1684
Reputation: 35440
What are some ways I can approach this problem?
This may be a little advanced, but you asked the question, and here is a possible way to approach the problem:
InOrder
could be a generic in-order traversal function, and whatever you want to do with the node that is visited, you pass that node to a user-defined function. That would have made your traversal much more generic and useful.
This has not been compiled, but shows you what a possible generic implementation of in-order traversal would look like, and how you may accomplish printing each node using operator <<
:
class WordTree
{
//...
public:
// generic, templated inorder traversal function
template <typename fn>
void InOrder(WordNode *cur, fn predicate)
{
if ( !cur )
return;
InOrder(cur->m_left, predicate);
// call the user-defined function
predicate(cur);
InOrder(cur->m_right, predicate);
}
friend std::ostream& operator<<(std::ostream &out, const WordTree& rhs);
//...
};
Now here is the implementation of the operator <<
and the user-defined function that will be used in WordTree::InOrder
:
// A helper functor to print one node
struct NodePrinter
{
std::ostream* strm;
// Initialize object with pointer to the stream
NodePrinter(std::ostream* s) : strm(s) {}
// function that is called by InOrder
void operator()(WordNode *cur)
{
*strm << cur->m_data << " " << cur->m_count << "\n";
}
};
std::ostream& operator<<(std::ostream &out, const WordTree& rhs)
{
// create instance of the functor
NodePrinter np(&out);
// call the InOrder function (assume that get_root() returns the pointer to the root node)
rhs.InOrder(rhs.get_root(), np);
return out;
}
Basically we've made InOrder
a generic function. The processing of the node that's visited is done by a user-defined function, function object, or even a lambda would (should) work (in this case, it is the NodePrinter
function object). This makes the in-order traversal much more flexible.
For example, if you wanted to concatenate each value in the node (assuming that the data portion is a string), and also get a total count:
std::string allNodes;
int count = 0;
//...
rhs.InOrder(rhs.get_root(), [&](WordNode *cur) { allNodes += cur->m_data; count += cur->m_count });
//..
std::cout << allNodes << "\n" << count;
The above is a lambda function that will be invoked whenever a node is encountered in the traversal.
Upvotes: 0
Reputation: 206637
Instead of
ostream& operator<<(ostream &out, const WordTree& rhs)
{
out << InOrder(&out, rhs.root);
return out;
}
use
ostream& operator<<(ostream &out, const WordTree& rhs)
{
// Invoke InOrder on the WordTree object.
// Use just out, not &out.
return rhs.InOrder(out, rhs.root);
}
It's unfortunate that InOrder
is not a const
member function. It should have been one.
One way to overcome the problem is to create a temporary object and use it.
ostream& operator<<(ostream &out, const WordTree& rhs)
{
// Invoke InOrder on the WordTree object.
// Use just out, not &out.
WordTree temp(rhs);
return temp.InOrder(out, temp.root);
}
Upvotes: 2