为什么我的重载<<运营商不工作?

时间:2016-01-15 10:53:05

标签: c++

我正在尝试了解如何正确地重载“<<”运算符,以便我可以使用

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

我在这里缺少什么?

3 个答案:

答案 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;

我创建自由功能并使其动态我在其中调用一些虚拟方法