为什么友元函数的返回类型会重载"<<"运营商必须参考?

时间:2015-04-17 17:35:38

标签: class c++11 overloading pass-by-reference friend

friend ostream &operator<<( ostream&, Complex& );

为什么我不能使用

friend ostream operator<<( ostream&, Complex&);

4 个答案:

答案 0 :(得分:2)

它没有必须,但有几个原因可以解释为什么这是一个常见的选择。

处理流的许多STL类和对象通常选择返回引用,因为这允许链接

class MyClass {
  public:

  MyClass(int v) : value(v) {}
  int value;

  friend MyClass &operator<<( MyClass&, MyClass& );

};

MyClass &operator<< (MyClass& a, MyClass& b) {
    a.value += b.value;
    return a;
}

int main() {
    MyClass a(2);
    MyClass b(3);
    MyClass c(5);

    a << b << c; // Chaining

    std::cout << a.value; // 10
}

Live Example

如果按价值返回,则无法在一行中完成

a << b; // Can't chain
a << c;

关于上述类别的另一个重要原因是,处理流意味着您无法复制流https://stackoverflow.com/a/6010930/1938163),因为它并不完全有道理。

这也意味着如果您将流对象保留在对象的状态(您将获得一个隐式删除的复制构造函数),则无法按值返回

class MyClass {
  public:

  MyClass(std::string str) {
    ss << str;
  }
  std::stringstream ss; // This CANNOT be copied

  friend MyClass operator<<( MyClass&, MyClass& );

};

MyClass operator<< (MyClass& a, MyClass& b) {
    a.ss << b.ss.str();
    return a; // Can't do this! Copy ctor is implicitly deleted due to ss
}

Live Example

在后者中,通过引用返回的常见情况几乎是必须的。

除了这些案件之外,没有人强迫你通过引用返回。它还取决于您的用例,更重要的是,关于您的对象如何管理其资源(请记住,如果按值返回,如果没有{{3>则可能会涉及析构函数参与)。

答案 1 :(得分:1)

按值返回意味着需要复制对象,否则它可能无效,因为原始(复制源)对象在调用析构函数后可能会自行清理,因此对于流可能会产生问题。通过引用返回可以避免这种情况,更重要的是,链接的调用将在每次ostream调用后共享相同的<<而不是新的流。

答案 2 :(得分:1)

std::ostream明确阻止了您复制它的能力。请注意,它有一个已删除的复制构造函数。

因此,如果您尝试按值返回它,则会导致编译器错误。

答案 3 :(得分:0)

这不是一个严格的要求。如果您使用非参考版本,

ostream << a << b << c

将为运算符的每次调用复制ostream对象&lt;&lt;什么时候回来。您可能没有理由想要复制而不是原始的ostream对象。