它经常被重载为类的朋友函数。有没有什么方法可以作为成员函数重载?
答案 0 :(得分:6)
有没有什么方法可以作为成员函数重载?
假设您有一个班级Foo
,并且您想使用:
Foo foo;
std::cout << foo;
不,它不能。
仅当第一个参数是类的对象时,成员函数重载才有效。对于流插入运算符,第一个参数是流,而不是类的对象。
如果您想使用:
Foo foo;
foo << std::cout;
是的,可以将其定义为成员函数。
在涉及派生类的情况下使用时,非成员函数和虚拟成员函数可以组合起来,效果很好。
struct Shape
{
// Member function that can be overridden by derived classes.
virtual std::ostream& operator<<(std::ostream& os) const = 0;
};
// Non-member function that makes use of member functions.
std::ostream& operator<<(std::ostream& os, Shape const& shape)
{
return shape << os;
}
struct Rectangle : public Shape
{
virtual std::ostream& operator<<(std::ostream& os) const
{
// Do the need full to stream a Rectangle.
// ...
return os;
}
};
struct Ellipse : public Shape
{
virtual std::ostream& operator<<(std::ostream& os) const
{
// Do the need full to stream an Ellipse.
// ...
return os;
}
};
用法:
Rectangle r;
Ellipse e;
std::cout << r << std::endl;
std::cout << e << std::endl;
答案 1 :(得分:0)
有没有什么方法可以作为成员函数重载?
没有。该功能的签名会阻止此选项。
// Binary operator where the stream object is left of '<<' and the object
// instance is right of '<<'
std::ostream& operator<<(std::ostream& lhs, const Foo& rhs)
为了说明这里的二元运算符+作为自由函数:
class Foo
{
};
Foo operator+(const Foo& lhs, const Foo& rhs)
{
// an appropriate implementation
}
int main()
{
Foo f1;
Foo f2;
// Uses the free function
Foo result = f1 + f2;
return 0;
}
但是作为成员函数实现它看起来像这样:
class Foo
{
public:
Foo operator+(const Foo& other) const
{
// an appropriate implementation
}
};
int main()
{
Foo f1;
Foo f2;
// The calling sequence is the same as before however 'f1' is logically
// the same as 'lhs' in the free function implementation example (i.e.,
// the first type in the binary operator must be the class type when
// implemented as a member function)
Foo result = f1 + f2;
return 0;
}
给定operator+
成员函数示例,更容易理解为什么std::ostream& operator<<(std::ostream& lhs, const Foo& rhs)
自由函数无法转换为等效成员函数。因为&#39; lhs&#39;将需要与std::ostream
相同的类型,但这只有在实现该类时才有可能,而在此示例中正在实现Foo
类。
答案 2 :(得分:0)
如果你想要足够严重,你可以使用成员函数重载,但它直接违反惯例,所以这样做会导致混淆。它还可以防止链接提取/插入操作符,并且不能用于读/写原始类型。
这背后的原因是调用作为成员函数重载的运算符意味着x << y;
被解释为x.operator<<(y);
,因此重载的运算符必须是左操作数的成员,而不是右边的操作数的成员。有可能这样做(iostream包含某些类型的重载),但它基本上不可能扩展(当它是左操作数时,所有这些重载都必须是iostream对象的一部分)。
如果要将其作为要读取/写入的对象的成员重载,则需要将读取/写入的对象作为左操作数。这意味着插入将从左到右而不是从右到左。为了保持理智至少有一些机会,你几乎肯定希望使用>>
进行插入,并使用<<
进行提取:
class my_class {
int x;
public:
bool operator<<(std::istream &is) {
// Note the reversal here. That's because we're defining this
// for a `my_class` on the left, and an iostream on the right,
// but the existing `>>` and `<<` use the reverse of that (iostream
// on the left).
is >> x;
return is.good();
}
bool operator>>(std::ostream &os) {
os << x;
return os.good();
}
};
my_class a;
a >> std::cout;
a << std::cin;
注意:我只提供 这个答案,指出技术上可以做到这一点,并说明如何做。如果你重新开始使用一个干净的平板并且真的设置使用成员函数,我可以看到可能可以选择这种方法 - 但即便如此,它也是对很多问题持开放态度。
特别是(如上所述)这不支持链接。由于插入和提取是作为左操作数的成员函数完成的,这也意味着它只适用于用户定义的类型,而不适用于任何基本类型(int,short,long,float,double,bool等)
底线:如果你想要足够严重,你可以在有限的情况下让它在有限的程度上工作 - 但既不好(没有链接)也不普遍(没有原始类型)。