为什么友元函数优于运算符的成员函数<<

时间:2010-03-16 21:57:26

标签: c++ operator-overloading

当您打算打印对象时,友方操作员<<用来。我们可以为运算符使用成员函数<< ?

class A {

public:
void operator<<(ostream& i) { i<<"Member function";}
friend ostream& operator<<(ostream& i, A& a) { i<<"operator<<"; return i;}
};


int main () {

   A a;
   A b;
   A c;
   cout<<a<<b<<c<<endl;
   a<<cout;
  return 0;
}

有一点是朋友功能使我们可以像这样使用它

cout<<a<<b<<c

还有其他什么原因?

4 个答案:

答案 0 :(得分:11)

对于二元运算符,您必须使用自由函数而不是成员函数,对于成员函数,左侧始终为*this,右侧作为另一个参数传递。

对于输出流操作符,左侧始终是流对象,因此如果您要流式传输到标准类而不是自己编写流,则必须提供自由函数而不是类的成员。

尽管可以将后向流操作符作为成员函数提供,然后像这样流出:

myObject >> std::cout;

你不仅违反了一个非常强大的库约定,正如你所指出的那样,由于>>的从左到右的分组,链接输出操作将不起作用。

编辑:正如其他人所说,虽然您必须将其设为免费功能,但如果无法根据班级实施流媒体功能,则只需friend即可公共接口。

答案 1 :(得分:10)

你别无选择 - 它必须是一个免费的功能。

但请注意,它不一定是friend函数。如果您确实需要授予私人访问权限,则只需要成为朋友。例如,我在编程比赛中使用以下内容:

template <class A, class B>
std::ostream& operator<<(std::ostream& os, const std::pair<A, B>& p)
{
  return os << '(' << p.first << ", " << p.second << ')';
}

无需成为好友,因为firstsecond可以公开访问。

答案 2 :(得分:1)

您的示例中的另一个原因 - 它必须是friend,因为这是在类定义中定义自由函数的唯一方法。如果你想要一个非朋友自由函数,它必须在类之外定义。

为什么你更喜欢在课堂上定义它?有时将所有操作符定义在一起很好:

struct SomeClass {
    // blah blah blah
    SomeClass &operator+=(const SomeClass &rhs) {
        // do something
    }
    friend SomeClass operator+(SomeClass lhs, const SomeClass &rhs) {
        lhs += rhs;
        return lhs;
    }
    // blah blah blah
    // several pages later
};

可能比以下用户更友好:

struct SomeClass {
    // blah blah blah
    SomeClass &operator+=(const SomeClass &rhs) {
        // do something
    }
    // blah blah blah
    // several pages later
};

SomeClass operator+(SomeClass lhs, const SomeClass &rhs) {
    lhs += rhs;
    return lhs;
}

这当然假定您在类定义中定义了相关的成员函数,而不是在那里声明它们并在.cpp文件中定义它们。

编辑:我使用+ =和+作为示例而没有真正考虑它,但您的问题是关于operator<<,它没有像operator+这样的任何密切相关的运算符。但如果operator<<调用与打印相关的一个或多个成员函数,您可能希望在定义它们的位置附近定义它。

答案 3 :(得分:0)

你做不到。但是如果你不希望它成为友方函数,那就把它变成一个自由函数,并根据类的公共接口来实现它。例如。

 ostream& operator<<(ostream& os, Myclass& obj)
{
   return obj.print(os);
}

ostream& MyClass::print(ostream& os)
{
   os << val; // for example.
   return os;
}