正如我在标题中指出的那样,这是一个令我困惑的问题,但我仍无法找到解决方法。
我创建了一个Point类,它有三个私有属性(_id,_x和_y)以及相关的公共get和set方法。 例如,我创建了三个点(G,H,R),其中点G是“父”。 H点是G点(克隆)的原型,R点是会合点(G + H)的结果(点数的加法)。
积分示例:
Point G ("pG", 3.5f, 6.5f);
Point H (G.prototype ()); H.setId ("pH");
Point R;
R = G + H;
程序正常工作,但不幸的是,在操作{R = G + H}之后,点G的_id属性成为R点的克隆属性,我不明白为什么会发生这种情况,因为评估是从右到右完成的左(H +,+ G,= R)。
问题是为什么G点属性会自行改变?
发生问题的代码:
#include <iostream>
#include <string>
using namespace std;
class Point
{
private:
string _id;
double _x;
double _y;
public:
Point(string id="undefined", double x = 0.00f, double y = 0.00f)
:_id(id), _x(x), _y(y){}
~Point(){}
public:
// Getters methods
string getId() const { return _id;}
double getX() const { return _x; }
double getY() const { return _y; }
void setId(string id) { _id = id; }
// Setters methods
void setX(double n = 0.00f) { _x = n; }
void setY(double n = 0.00f) { _y = n; }
Point prototype() { return Point(_id, _x, _y); }
Point operator+ (const Point& p)
{
cout << "Operator + called, returning a new object" << endl;
return Point
(
_id.append("+").append(p._id),
_x+p._x,
_y+p._y
);
}
Point operator= (const Point& p)
{
cout << "Operator = called, returning a new object Point(p._id, p._x, p._y)" << endl;
_id=p._id;
_x=p._x;
_y=p._y;
return *this;
}
};
int main()
{
Point G("G",10.0f, 10.0f);
Point H(G.prototype()); H.setId("H");
Point R;
R = G + H;
cout << "object Point {id: " << G.getId() << ", x: " << G.getX() << ", y: " << G.getY() << "}" << endl;
cout << "object Point {id: " << H.getId() << ", x: " << H.getX() << ", y: " << H.getY() << "}" << endl;
cout << "object Point {id: " << R.getId() << ", x: " << R.getX() << ", y: " << R.getY() << "}" << endl;
return 0;
}
提前致谢!
答案 0 :(得分:2)
Point operator+ (const Point& p)
{
cout << "Operator + called, returning a new object" << endl;
return Point
(
_id.append("+").append(p._id), // HERE
_x+p._x,
_y+p._y
);
}
在此行中,您修改_id
对象的this
属性。根据经验,binary +运算符应该是const成员或 - IMO清理器 - 一个带有两个const引用参数的静态方法。
顺便说一句,您可以通过对它们应用+运算符(_id + "+" + p._id
)来在C ++中添加字符串。
答案 1 :(得分:2)
如果将二进制算术运算符实现为成员,则应考虑将运算符设为const
成员。这将在您的实现中捕获明显的修改(实现是为了避免包含不相关的代码而实行的):
Point Point::operator+ (const Point& p) const
{
cout << "Operator + called, returning a new object" << endl;
return Point
(
_id.append("+").append(p._id),
_x+p._x,
_y+p._y
);
}
操作_id.append("+")
实际上在this->_id
上运行,即左手操作数的_id
成员。由于您的成员运算符不是const
,因此编译器允许您进行修改。这可能不是你想要做的。你可能更愿意写:
Point Point::operator+ (const Point& p) const
{
cout << "Operator + called, returning a new object\n";
return Point
(
_id + "+" + p._id,
_x+p._x,
_y+p._y
);
}
...创建一个具有所需值的合适临时字符串(我也替换了excessive use of std::endl
)。
答案 2 :(得分:1)
operator+
重载中的这一行:
_id.append("+").append(p._id),
你必须在这里非常小心,你当前在一个对象中(在你的例子中,这将是G
对象)。 append
实际上会更改本地字符串,因此您的代码会追加+
然后p._id
,然后将其深度复制到返回的值。
快速解决方法是将其更改为包含所需内容的临时文件:
_id + "+" + p._id
为了避免将来出现这样的问题,你应该将操作符重载声明为朋友方法,这样就可以非常清楚你在操作什么了。
friend Point operator+ (const Point& lhs, const Point& rhs)
{
cout << "Operator + called, returning a new object" << endl;
return Point
(
lhs._id.append("+").append(rhs._id), //COMPILER ERROR! We're modifying the const "lhs"!
lhs._x+rhs._x,
lhs._y+rhs._y
);
}
所以我们将其改为:
friend Point operator+ (const Point& lhs, const Point& rhs)
{
cout << "Operator + called, returning a new object" << endl;
return Point
(
lhs._id + "+" + rhs._id, // no longer modifying lhs -- all is well!
lhs._x+rhs._x,
lhs._y+rhs._y
);
}