为什么以及如何重载operator<<用于印刷

时间:2015-01-09 23:41:23

标签: c++ operator-overloading friend

我已经编写了一个用于实现堆栈的程序。我有一个显示功能。

这是我首先编写显示功能的方式:

template <class t>
void Mystack<t>::display()
{
    for (int i = 0; i <= top; i++)
    {
        std::cout << input[i] << " ";
    }
}

然后开发人员建议我编写一个更通用的显示函数。所以我把显示功能写成:

template <class T>
void Mystack<T>::display(std::ostream &os) const         
{
    for (int i = 0; i <= top; i++)
    {
        os << input[i] << " ";
    }
}

根据我的理解,编写上述功能的好处是,现在我有一个通用的显示功能,我可以用来向控制台或文件显示数据。

问题1 :我的理解是否正确?

现在另一个建议是编写类似的函数:

template <typename T>
friend std::ostream& operator<<(std::ostream& s, Mystack<T> const& d) {
    d.display(s);
    return s;
}

问题2 :具有上述显示功能有什么好处?通过具有上述显示功能,我能够实现什么?

4 个答案:

答案 0 :(得分:6)

对于问题1,您的理解是正确的,但真正的改进来自问题2的写作建议:

template <typename T>
friend std::ostream& operator<<(std::ostream&, Mystack<T> const& );

这将让任何人以与传输其他内容相同的方式流式传输您的类型的对象:

std::cout << "Hi, my stack is " << stack << ", it has size " << stack.size();

到他们想要的任何流:

some_file << "Result of computation is: " << stack;
std::cerr << "Error, invalid stack: " << stack << ", expected: " << some_other_thing;

答案 1 :(得分:5)

首先 - 。通过获取std::ostream&参数,您也可以输出到任何派生流,例如std::ofstreamstd::coutstd::cerr

使用operator<<可以使用该运算符。考虑:

mystack<int> stackOfInts;
//...
std::cout << "Stack contents:" << std::endl << stackOfInts << std::endl;

它比“标准”函数调用更具惯用性。

返回流允许操作符的链接,如上例所示。链接有效地将调用结果传递给另一个operator<<

operator<<( operator<<("Stack contents:", std::endl), stackOfInts ) );

如果此次重载调用也未返回std::ostream&,则无法执行此操作:

operator<<( resultOfAbove, std::endl );

声明函数friend允许其定义使用私有成员。如果没有这个,你就必须为每个私人成员写一个公共的getter。

答案 2 :(得分:1)

两种显示功能基本相同。你调用函数的方式不同。 使用第一个函数,您可以通常的方式调用函数:

std::cout<<"This is MyStack (with first method): ";
m.display(std::cout);      //function call
std::cout<<std::endl;

使用第二个功能,您可以使用操作员调用功能&#34;&lt;&lt;&#34;:

std::cout<<"This is MyStack (with second method): "
               <<m   //function call
               <<std::endl;

但我个人更喜欢第二个。因为它对我来说比较熟悉。

答案 3 :(得分:0)

关于问题2 ,如果您有一个基类和许多派生类,并希望在基础中只编写一次operator<<,那么这就是您的选择。类。然后,如果在类层次结构中将display()函数声明为virtual,则可以在运行时选择正确的显示函数。也就是说,如果您有类似

的内容
Derived foo;
std::cout << foo;

然后Base::operator<<将调用Derived::display(),因为它被标记为虚拟,foo通过引用传递。当你有一个类层次结构并且不希望为每个派生类重载operator<<时,这是要走的路。

这是避免代码重复的常见技巧。参见

Making operator<< virtual?

有关详细信息,请参阅StackOverflow上的