当<<
运算符重载的返回类型为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;
}
答案 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;
}