重载<<运算符作为“朋友”函数以打印BST-C ++

时间:2018-08-16 22:07:31

标签: c++ operator-overloading binary-search-tree

我正在尝试重载<<运算符,以打印出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;
}

我可以通过哪些方法解决此问题?

2 个答案:

答案 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);
}

更新,以回应OP的评论

不幸的是,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函数,只要遍历中遇到某个节点,就会调用该函数。