为什么以及如何重载操作员<<进行打印
Why and how to overload operator<< for printing
我写了一个实现堆栈的程序。我有一个显示功能。
这就是我最初编写显示函数的方式:
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:拥有上述显示功能有什么好处?通过上述显示功能,我究竟可以实现什么?
对于问题 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;
首先 - 是的。通过获取 std::ostream&
参数,您也可以输出到任何派生流,如 std::ofstream
或 std::cout
、 std::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
允许其定义使用私有成员。如果没有这个,你将不得不做一些事情,比如为每个私人成员编写一个公共获取器。
两者的显示功能基本相同。不同的是调用函数的方式。使用第一个函数,您可以以通常的方式调用函数:
std::cout<<"This is MyStack (with first method): ";
m.display(std::cout); //function call
std::cout<<std::endl;
使用第二个函数,您可以使用运算符"<<"调用函数:
std::cout<<"This is MyStack (with second method): "
<<m //function call
<<std::endl;
但我个人更喜欢第二个。因为它对我来说更熟悉。
与问题 2 一样,如果您有一个基类和大量派生类,并且只想在基类中编写一次operator<<
,则可以采用此方法。然后,如果将display()
函数声明为沿类层次结构virtual
,则可以在运行时选择正确的显示函数。也就是说,如果你有类似的东西
Derived foo;
std::cout << foo;
然后Base::operator<<
将调用Derived::display()
,因为它被标记为虚拟,并且foo
通过引用传递。当您具有类层次结构并且不想为每个派生类重载operator<<
时,这是要走的方法。
这是避免代码重复的常用技巧。看
让操作员<<虚拟?
在 StackOverflow 上了解更多详情。
- 请解释这句话(cout<<1+int((a<b)^((b-a)&1) )<<endl
- 呼叫运营商<<临时
- 如何防止clang格式在流运算符调用之间添加换行符<<
- <<操作员在下面的行中工作
- C++ 与操作员不匹配<<
- 模板操作员&lt;未打电话
- C 建造者Clang STD :: Sill,找不到超载的操作员&lt;
- 为什么STD :: MAP需要操作员&lt;以及我如何写一个
- 为什么“操作员”需要const但不是为“运营商&lt;”
- 左角支架解释为操作员&lt;而不是模板参数
- 超载操作员&lt;&lt; - 必须是二进制操作员
- 为什么COUT在朋友函数中不起作用,该功能超载了操作员&lt;&lt;这是一个iStream运算符
- &lt;&lt;&lt;的这些超载有什么区别操作员
- (C 14)操作员&lt;&lt;超负荷无法正如智能指针向量所预期的那样工作
- 带有GMP的CodeBlocks,segfault with&lt;&lt;操作员和MP*_Class
- &lt;&lt;操作员在C 中超载错误
- Visual C 构建器图案插入操作员`&lt;&lt;`样式
- 超载&LT的正确方法;操作员
- 在尝试超载&lt;&lt;时链接错误2005和1169操作员
- C++标准::cout和<<操作员,优先级