我正在尝试了解如何正确地重载“<<”运算符,以便我可以使用
std::cout << my_object;
打印有用的调试消息。特别是,我需要实现&lt;&lt;对于我的每个子类,所以我声明&lt;&lt;在超类中是虚拟的。
现在我坚持使用以下代码
#include <iostream>
using namespace std;
class Shape {
public:
virtual ~Shape() { };
virtual ostream& operator<<(std::ostream &strm) = 0;
};
class Square : public Shape {
int size;
public:
Square() { size = 10; }
~Square() { }
ostream& operator<<(std::ostream &strm) {
return strm << "a square with size " << size;
}
};
int main() {
Square *my_square = new Square();
cout << "my_square is " << my_square << "\n";
}
(我认为)应该有效,但不是。使用“&lt;&lt;”时我得到了什么是打印my_square的指针值,而不是重载的&lt;&lt;
$ ./a.out
my_square is 0xcacc20
我在这里缺少什么?
答案 0 :(得分:5)
operator<<
无法成为会员功能。这是因为参数的顺序。流必须先来。
调用重载运算符时,例如:
os << object;
编译器将尝试查找
os.operator<<(object);
和
operator<<(os, object);
(这个规则可能相当复杂,我不打算在这里描述它们。)
因为流始终位于左侧,所以永远不会找到您的成员函数,因为它必须被称为:
object.operator<<(os);
您需要编写一个免费的功能,如:
ostream& operator<<(std::ostream &strm, Square const& square) {
return strm << "a square with size " << square.size();
}
(其中Square::size()
返回size
成员)。
然后你需要记住取消引用你的指针:
std::cout << *my_square << '\n';
虽然我认为没有理由在这个例子中动态分配my_square
。只需将它作为局部变量粘贴在堆栈上即可。
如果此处的目标最终是能够打印任何 Shape&
,并且打印输出跟随&#34;真实&#34;类型,您需要创建:
virtual std::ostream& print(std::ostream&) const = 0;
在Shape
基类中,并在每个派生类中重写它,然后有一个自由函数:
std::ostream& operator<<(std::ostream& os, Shape const& shape)
{
return shape.print(os);
}
通常建议在类型非成员函数上创建所有二元运算符,这样两个参数都被平等对待,并且操作仍然是可交换的。请参阅Scott Meyers, Effective C ++(第3版),第24项,(or find a summary online)。
答案 1 :(得分:3)
正如其他人所指出的,问题是operator <<
不能成为成员函数(因为参数的顺序)。执行此操作的规范方法是让operator <<(const Shape&)
调用Shape
中的虚拟函数
class Shape {
friend ostream& operator<<(std::ostream& str, const Shape& shape);
virtual void do_print(ostream& str) = 0;
public:
virtual ~Shape() { };
};
ostream& operator<<(std::ostream& str, const Shape& shape) {
shape.do_print(str);
return str;
}
请注意, 是合法的,do_print
是私有的,即使它(必须)被派生类覆盖。如果你愿意,你可以保护它。
答案 2 :(得分:1)
我在这里缺少什么?
您已经创建了运算符,它将您的类作为第一个参数,并将流作为第二个参数。
my_square << std::cout;
我创建自由功能并使其动态我在其中调用一些虚拟方法