我正在尝试重载<<
运算符,以打印出BST的私有数据(包含单词和计数)。我必须将此运算符设为我的friend
类的WordTree
非成员函数,并且不能定义任何其他public
成员函数(这是学校的作业)。
这是我的operator<<
朋友功能:
ostream& operator<<(ostream &out, const WordTree& rhs)
{
out << InOrder(&out, rhs.root); // does not work as InOrder is private member function
return out;
}
这是我的private
函数InOrder
,它在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;
}
我可以通过哪些方法解决此问题?
答案 0 :(得分:2)
代替
ostream& operator<<(ostream &out, const WordTree& rhs)
{
out << InOrder(&out, rhs.root);
return out;
}
使用
ostream& operator<<(ostream &out, const WordTree& rhs)
{
// Invoke InOrder on the WordTree object.
// Use just out, not &out.
return rhs.InOrder(out, rhs.root);
}
不幸的是,InOrder
不是const
成员函数。应该是一个。
解决该问题的一种方法是创建一个临时对象并使用它。
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);
}
答案 1 :(得分:0)
我可以通过哪些方法解决此问题?
这可能有点高级,但是您问了这个问题,这是解决问题的一种可能方法:
InOrder
可以是一般的有序遍历函数,无论您要对被访问的节点执行什么操作,都需要将该节点传递给用户定义的函数。那将使遍历更加通用和有用。
尚未编译,但向您显示了可能的按顺序遍历的通用实现是什么样的,以及如何使用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);
//...
};
现在这是operator <<
的实现和将在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;
}
基本上,我们已将InOrder
设为通用函数。访问的节点的处理是通过用户定义的函数,函数对象甚至lambda(应该)工作的(在这种情况下,它是NodePrinter
函数对象)。这使得有序遍历更加灵活。
例如,如果您想连接节点中的每个值(假设数据部分是字符串),并获得总数:
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;
上面是一个lambda函数,只要遍历中遇到某个节点,就会调用该函数。