声明一个接受并返回 "ostream&" 的函数与重载 operator<< 相比有什么用处?

3

我曾遇到一些函数,它们不是通过重载运算符<<来与cout一起使用,而是声明一个接受ostream并返回ostream的函数。

例如:

#include <iostream>

class A {
private:
  int number;
public:
  A(int n) : number(n) {}
  ~A() {}
  std::ostream& print(std::ostream& os) const;
  friend std::ostream& operator<<(std::ostream& os, const A a);
};

一个实现的例子:

std::ostream& A::print(std::ostream& os) const {
  os << "number " << number;
  return os;
}

std::ostream& operator<<(std::ostream& os, const A a) {
  os << "number " << a.number;
  return os;
}

现在,如果我运行它,我可以在不同的情况下使用不同的函数。例如:
int main() {
  A a(1);

  std::cout << "Object.";  a.print(std::cout);
  std::cout << "\n\n";
  std::cout << "Object." << a;
  std::cout << "\n\n";

  return 0;
}

输出:

Object.number 1

Object.number 1

似乎没有必要使用打印函数,因为你只能单独使用它或在“cout链”的开头使用它,但永远不能在中间或结尾使用它,这使得它变得无用。如果找不到其他用途,使用一个“void print()”函数是否更好呢?


使用真的很让我烦恼。我看不到任何有效的理由。 - Lightness Races in Orbit
那不是完全正确的。你可以嵌套函数而不是链式调用它。a.print(std::cout << "Object."); - N_A
我会非常生气,如果看到这样的代码:a.print(a.print(std::cout << "before" ) << "in between" ) << "after"; - MSalters
4个回答

7

当涉及到继承层次结构时,使用继承层次结构是有意义的。您可以将print方法设置为虚拟的,在基类的运算符中委派给虚拟方法进行打印。


谢谢。虽然它不需要是虚拟的,而应该像Ernest在另一个答案中写的那样使用,但我理解了你的观点。这帮了我很多,谢谢。 - Mazen Harake

2

如果operator<<()看起来像这样会更有意义:

std::ostream& operator<<(std::ostream& os, const A a) {
    return a.print(os);
}

那么 operator<<() 就不需要成为友元函数了。


感谢您提供的代码示例。这很有道理,不过您回答问题的方式有点奇怪 :) 如果不是因为它在“答案”下面,我会认为这更像是对我的示例的评论 ;) - Mazen Harake

0

operator<< 的使用假定只有一种合理的方式来打印数据。有时候这是正确的。但有时候,我们可能希望以多种有效的方式输出数据:

#include <iostream>
using std::cout; using std::endl;
int main()
{
  const char* strPtr = "what's my address?";
  const void* address = strPtr;

  // When you stream a pointer, you get the address:
  cout << "Address: " << address << endl;

  // Except when you don't:
  cout << "Not the address: " << strPtr << endl;
}

http://codepad.org/ip3OqvYq

在这种情况下,你可以选择其中一种方式作为“途径”,并使用其他函数(例如print?)来处理其余部分。或者你可以只使用print来处理所有内容。(或者你可以使用流标志来触发所需的行为,但是这样设置和保持一致性要更困难。)

0

一个函数如果可以作为cout链的起点,相比于不能作为起点的函数,在其他条件相同的情况下肯定更有用。

我实现了几个函数,它们的签名与您描述的类似,因为operator<<只是一个名称,有时我需要以多种不同的方式流式传输对象。我有一种格式用于在屏幕上打印,另一种格式用于保存到文件中。对于两者都使用<<操作符可能会很麻烦,但至少为其中一个操作选择一个可读性高的名称很容易。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接