<< 运算符重载返回 std::string 时出错

Error with << operator overload returning a std::string

<< 运算符重载的 return 类型为 std::string 时,我无法理解编译器指出错误的原因。你能帮我理解一下吗?

Bellow 是一个可重现的例子,它给出了一个巨大的错误。

class XY
{
    int X__;
    int Y__;
 public:
    XY(int x, int y):X__(x), Y__(y){}
    ~XY(){}

    std::string operator<<(const XY_cartesiano& c)
    {
        std::stringstream ss;
        ss << "{ " << X__ << ", " << Y__ << " }";
        return ss.str();
    }

    int x() const{return X__;}
    int y() const{return Y__;}
};

void main()
{

XY a(1,2);
std::cout << a;
}

让我们以这样的事情为例:

cout << "My number is " << 137 << " and I like it a lot." << endl;

这被解析为

((((cout << "My number is ") << 137) << " and I like it a lot.") << endl);

特别注意,表达式 cout << "My number is " 必须求值,这样当我们尝试用 << 137 插入 137 时,其含义是 "take 137 and send it to cout."

想象一下,如果 cout << "My number is " 是 return 一个 string。在这种情况下,<< 137 位将尝试在左侧的 string 和右侧的 int 之间使用 << 运算符,这在 C++ 中没有明确定义。

惯例是让流插入运算符 operator << return 引用任何左侧流,以便这些操作很好地链接。这样,<< 137 左侧的东西最终就是 cout 本身,所以上面的代码最终实际上是一系列链式调用,用于将东西插入 cout。因此,这些函数的签名通常如下所示:

ostream& operator<< (ostream& out, const ObjectType& myObject) {
     // ... do something to insert myObject into out ... //
     return out;
}

现在,一切都正确链接了。请注意,此函数是一个自由函数,而不是成员函数,左侧是 ostream 类型,右侧是 class 类型。这是执行此操作的常规方法,因为如果您尝试将 operator << 重载为成员函数,则左侧将是 class 类型的操作数,这与流插入的方式相反应该工作。如果您在实现此功能的过程中需要专门访问您的 class 的私有字段,请将其加为好友:

class XY {
public:
      ...
      friend ostream& operator<< (ostream& out, const XY& myXY);
};

ostream& operator<< (ostream& out, const XY &myXY) {
    ...
    return out;
}

在您的案例中重载 << 运算符的正确方法是

ostream& operator<<(ostream& os, const XY& c)  
{  
    os << c.X__ <<" "<< c.Y__ ;
    return os;  
}

您重载 operator<< 的方式与您打算将运算符与 std::ostream 对象(例如 std::cout.

一起使用时必须遵循的约定不兼容]

事实上,您operator<<的签名与流完全无关!它只是 XY 的一个成员函数,它接受另一个 XY (然后它不使用),return 是一个字符串并且有一个不正常的名字。理论上您可以这样称呼它:

XY a(1,2);
XY b(1,2);
std::string x = (a << b);

重载 operator<< 以用于流的正确方法是使运算符成为非成员函数,添加流引用参数和 return 对流参数的流引用。您也不需要字符串流;你直接写入你得到的流:

#include <iostream>

class XY
{
    int x;
    int y;
public:
    XY(int x, int y) : x(x), y(y) {}

    int X() const { return x; }
    int Y() const { return y; }
};

std::ostream& operator<<(std::ostream& os, XY const& c)
{
    os << "{ " << c.X() << ", " << c.Y() << " }";
    return os;
}

int main()
{
    XY a(1,2);
    std::cout << a;
}