我正在尝试将operator<<
重载为成员函数。只要这样做就可以了:
friend ostream& operator<<(ostream& os, const MyClass& myClass);
:
ostream& operator<<(ostream& os, const MyClass& myClass)
{
return myClass.print(os);
}
但是,如果我尝试关闭friend
并使其成为成员函数,那么它会抱怨operator<<
只能接受一个参数。为什么呢?
ostream& MyClass::operator<<(ostream& os, const MyClass& myClass)
{
return myClass.print(os);
}
我在this question读到它不能成为会员功能,但不确定原因?
答案 0 :(得分:44)
当作为成员函数重载时,a << b
被解释为a.operator<<(b)
,因此它只需要一个显式参数(this
作为隐藏参数)。
因为这要求重载是用作左操作数的类的一部分,所以它对普通ostream
等没用。这需要您的重载是ostream
类的一部分,而不是类的一部分。由于您不允许修改ostream
,因此您无法执行此操作。这只留下全球超载作为替代方案。
然而,有一个相当广泛使用的模式,你在全局范围内重载运算符,但是调用它是一个成员函数:
class whatever {
// make this public, or the global overload a friend.
std::ostream &write(std::ostream &dest) const {
// write self to dest
}
};
std::ostream &operator<<(std::ostream &os, whatever const &w) {
return w.write(os);
}
当您需要多态行为时,这尤其有用。你不能让重载的运算符本身变成多态,但是你使它调用virtual
的成员函数,所以无论如何它都是多态的。
write
成员公开,并让全局运营商调用它。由于它是公开的,我们不需要做任何特别的事情让操作员使用它:
class myClass {
public:
std::ostream &write(std::ostream &os) const {
// write stuff to stream
return os;
}
};
std::ostream &operator<<(std::ostream &os, myClas const &m) {
// since `write` is public, we can call it without any problem.
return m.write(os);
}
第二种方法是将write
设为私有,并声明operator<<
朋友为其提供访问权限:
class myClass {
// Note this is private:
std::ostream &write(std::ostream &os) const {
// write stuff to stream
return os;
}
// since `write` is private, we declare `operator<<` a friend to give it access:
friend std::ostream &operator<<(std::ostream &, myClass const &);
};
std::ostream &operator<<(std::ostream &os, myClas const &m) {
return m.write(os);
}
第三种可能性几乎与第二种可能性相同:
class myClass {
// Note this is private:
std::ostream &write(std::ostream &os) const {
// write stuff to stream
return os;
}
// since `write` is private, we declare `operator<<` a friend to give it access.
// We also implement it right here inside the class definition though:
friend std::ostream &operator<<(std::ostream &os, myClas const &m) {
return m.write(os);
}
};
第三种情况在C ++中使用了一种名为“名称注入”的相当奇怪(并且鲜为人知)的规则。编译器知道friend
函数不能成为类的一部分,因此不是定义成员函数,而是将该函数的名称“注入”到周围的作用域(在这种情况下为全局作用域) 。尽管在类定义中定义了operator<<
,但它根本不是 成员函数 - 它是一个全局函数。
答案 1 :(得分:10)
您可以将operator<<
重载为成员函数。但你不能写一个成员operator<<
,左边有一个ostream,右边是你的班级。
当你创建一个(非静态)成员函数时,有一个隐含的第一个参数,即调用对象。 operator<<
是二进制的,所以它只需要2个参数。如果你把它作为一个成员函数,你只能给它一个paremeter,因为它已经有一个(调用对象)。由于该调用对象始终是第一个参数,因此您不可能将输出运算符编写为(非静态)成员(至少不是该特定函数的标准形式),因为对于这种情况,ostream需要成为第一个论点。
答案 2 :(得分:1)
可以这样想:当你想要流式传输到ostream时,你正在调用&lt;&lt;流对象上的operator 。而且你不能直接修改ostream的'私有'方法。因此,您必须创建一个重载版本,并使其成为朋友。
当您创建自己的运算符时&lt;&lt;你班上的方法,你正在创建一个&lt;&lt;将在您的类上运行的方法,而不是ostream对象。我猜你可以在你的班级内部保存一个ostream并流式传输,但你写这样的链式语句会有困难:a << b << c
。