我正在按照printing pattern for a class hierarchy中所述实现C++ FAQ。在FAQ中,打印函数在基类中声明如下:
protected:
virtual void printOn(std::ostream& o) const = 0; // pure virtual
// -- or --
virtual void printOn(std::ostream& o) const; // plain virtual
我正在考虑实现
printOn
方法的纯虚拟版本,但有所不同。我想将返回类型从void
更改为std::ostream&
,如下所示:protected:
virtual std::ostream& printOn(std::ostream& o) const;
如我所见,这种方法的优点是可以使用链接方法将基类的输出更容易地合并到派生类的输出中。这是一个例子:
std::ostream& DerivedClass::printOn(std::ostream& stream) const
{
return stream
<< "<DerivedClass>" << '\n'
<< BaseClass::printOn(stream)
<< "<member_one>" << member_one_ << "</member_one>" << '\n'
<< "<member_two>" << member_two_ << "</member_two>" << '\n'
<< "</DerivedClass>" << std::endl;
}
相比之下,这是如果在FAQ中将虚拟
DerivedClass::printOn
方法声明为BaseClass::printOn
的情况下void
的外观:void DerivedClass::printOn(std::ostream& stream) const
{
stream << "<DerivedClass>" << '\n';
BaseClass::printOn(stream);
stream
<< "<member_one>" << member_one_ << "</member_one>" << '\n'
<< "<member_two>" << member_two_ << "</member_two>" << '\n'
<< "</DerivedClass>" << std::endl;
}
问题:有人对我建议的
printOn
返回类型的修订版有任何陷阱吗? 最佳答案
如果BaseClass::printOn(stream)
返回std::ostream &
,那么您将无法编写
stream << ... << BaseClass::printOn(stream) << ...;
您必须写:
stream << ...;
BaseClass::printOn(stream) << ...;
显然,这几乎比返回
void
的情况更好。您可以使用无操作流输出运算符返回类型:struct noop_manipulator {
noop_manipulator(std::ostream &) {}
friend inline std::ostream &operator<<(std::ostream &os, const noop_manipulator &) {
return os;
}
};
noop_manipulator DerivedClass::printOn(std::ostream& stream) const
{
return stream << ...;
}
另外,您也可以使用以下语法:
void DerivedClass::printOn(std::ostream& stream) const
{
return stream << "<DerivedClass>" << '\n',
BaseClass::printOn(stream), stream
<< "<member_one>" << member_one_ << "</member_one>" << '\n'
<< "<member_two>" << member_two_ << "</member_two>" << '\n'
<< "</DerivedClass>" << std::endl;
}
所有这些方法的缺点是它们使您无法使用父类(super class)虚拟调用,这是非常不寻常的,因此实际上应该使其尽可能清晰。所描述的打印模式本身非常不常见;除非您已经具有虚拟继承层次结构,否则派生类通常具有自己的
operator<<
并通过operator<<
调用基类static_cast
到基类引用。