<<错误operator重载返回std :: string

时间:2017-10-28 19:22:55

标签: c++ operator-overloading iostream

<<运算符重载的返回类型为std::string时,我很难理解编译器控制错误的原因。你能帮我理解一下吗?

贝娄是一个可重复的例子,它给出了一个巨大的错误。

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;
}

3 个答案:

答案 0 :(得分:4)

让我们以此为例:

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时,意思是“取137并将其发送到cout。 “

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

惯例是让流插入运算符operator <<返回对左侧流的引用,以便这些操作链接良好。这样,<< 137左侧的内容最终成为cout本身,因此上述代码最终基本上是一系列链接调用,以便将内容插入cout。因此,这些函数的签名通常如下所示:

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

现在,一切都正常连锁。请注意,此函数是自由函数,而不是成员函数,左侧是ostream类型,右侧是类的类型。这是执行此操作的常规方法,因为如果您尝试将operator <<重载为成员函数,则左侧将是您的类类型的操作数,这是从流插入应该如何工作的向后。如果您需要在实现此功能的过程中专门访问您班级的私人字段,请将其设为好友:

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

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

答案 1 :(得分:1)

在您的情况下正确重载<<运算符的方法是

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

答案 2 :(得分:1)

您的重载<canvas id="textCanvas" width="700" height="150" style="border:1px solid #d3d3d3;"> <script> function parse_html(ctx, s, x0, y0, align, font, fontsize, col) { // 2d canvas context, string, pos.x, pos.y, left/right/center, font, font height, color // Convert html code to a series of individual strings, each displayable by fillText(). font = 'px '+font var lines = [] var line = [0] var part = '' // the text element preceding a '<' var cmd = '' var bold = false var italic = false var sup = false var sub = false var x = 0, y = 0 var dx, start var legal = ['b', 'strong', 'i', 'em', 'sup', 'sub'] function add_part() { var style = '' var fs = fontsize if (bold) style += 'bold ' if (italic) style += 'italic ' if (sup || sub) { fs = 0.8*fontsize if (sup) y -= 0.3*fontsize // y increases downward in 2D canvas else y += 0.3*fontsize } ctx.font = style+fs+font dx = ctx.measureText(part).width line.push([x, y, ctx.font, part]) part = '' x += dx } function end_line() { if (part !== '') add_part() line[0] = x lines.push(line) line = [0] x = y = 0 } for (var i=0; i<s.length; i++) { var c = s[i] if (c == '\n') { end_line() } else if (c != '<') { part += c // a part of the text } else { // encountered '<' //if (part !== '') add_part() start = i+1 i++ cmd = s[i] var end = false if (cmd == '/') { cmd = '' end = true } var ok = true for (i=i+1; i<s.length; i++) { if (s[i] == '<') { // This means that the intial '<' did not start a command i = i-1 // back up part += '<'+cmd add_part() ok = false // signal that we encountered '<' break } if (s[i] == '>') break cmd += s[i] } if (!ok) continue if (cmd == 'br' || cmd == 'br/') { end_line() } else { if (legal.indexOf(cmd) >= 0 && part !== '') add_part() switch (cmd) { case 'b': case 'strong': bold = !end break case 'i': case 'em': italic = !end break case 'sup': sup = !end if (end) y = 0 break case 'sub': sub = !end if (end) y = 0 break default: part += '<'+cmd+'>' } } } } if (part.length > 0) line.push([x, y, fontsize+font, part]) ctx.font = fontsize+font line[0] = x + ctx.measureText(part).width lines.push(line) function rgb_to_html(rgb) { // convert RGB 0-1 to html 0-255 var r = Math.floor(255 * rgb[0]) var g = Math.floor(255 * rgb[1]) var b = Math.floor(255 * rgb[2]) return 'rgb(' + r + ',' + g + ',' + b + ')' } var width, L var nline = 0 // Each line in lines starts with the total width of the line, followed by // elements of the form {x, y, font, text}, where x and y start at zero. var maxwidth = -1 for (L in lines) { if (lines[L][0] > maxwidth) maxwidth = lines[L][0] } for (L in lines) { y0 += nline*1.2*fontsize nline++ for (var p in lines[L]) { var k = lines[L][p] if (k[1] === undefined) { width = k continue } ctx.font = k[2] ctx.fillStyle = rgb_to_html(col) switch (align) { case 'left': x = x0 + k[0] y = y0 + k[1] break case 'center': x = x0 + k[0] - width/2 y = y0 + k[1] break case 'right': x = x0 + k[0] - maxwidth y = y0 + k[1] break default: throw new Error(align+' is not a possible alignment option.') } ctx.fillText(k[3], x, y) } } } var c = document.getElementById("textCanvas") var ctx = c.getContext("2d") var s = 'The <b><i>quick</i> fox</b> <i>jumps.</i><br><i>M</i><sub>sys</sub> >= 10<sup>-3</sup> kg' parse_html(ctx, s, 350, 50, 'center', 'Verdana', 30, [0,0,1]) </script> 的方式与您打算将运算符与operator<< std::ostream std::cout对象一起使用时必须遵循的约定不相容。

事实上,您的operator<<签名根本与流无关!它只是XY的成员函数,它接受另一个XY(然后它不使用),返回一个字符串并具有一个不正确的名称。以下是理论上称之为:

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

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

#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;
}