1

我正在实现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;
}

相比之下,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

4

1 回答 1

2

如果BaseClass::printOn(stream)返回 astd::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;
}

所有这些方法的缺点是它们掩盖了您对超类虚拟调用的使用,这是非常不寻常的,因此应该尽可能清楚地说明。所描述的印刷图案本身就很不寻常;除非您已经拥有虚拟继承层次结构,否则派生类通常拥有自己的继承并通过基类引用operator<<调用基类。operator<<static_cast

于 2013-02-14T21:45:12.393 回答