[英]C++ an issue with returning a temporary object
您好,我用C ++大约一个月大了,所以如果这个问题太琐碎,请原谅。
#include <iostream>
using namespace std;
class Point {
int x,y;
public:
Point(int x_val = 0,int y_val = 0) :x(x_val),y(y_val) { }
Point(Point& copy) : x(copy.x), y(copy.y) { }
void showLocation() const { cout << "[" << x << "," << y << "]" << endl; }
friend Point operator+(const Point& p1, const Point& p2);
friend Point operator-(const Point& p1, const Point& p2);
Point operator-(Point& p2) { // (1)
Point(x-p2.x, y-p2.y).showLocation();
return Point(x-p2.x, y-p2.y);
}
};
Point operator+(const Point& p1, const Point& p2) { // (2)
Point pos(p1.x+p2.x, p1.y+p2.y);
return pos;
}
Point operator-(const Point& p1, const Point& p2) { // (3)
return Point(p1.x-p2.x, p1.y-p2.y);
}
int main() {
Point p1(3,4);
Point p2(2,5);
(p1+p2).showLocation();
//(p1-p2).showLocation();
operator-(p1,p2);
}
因此,这是一个用于练习操作符重载的简单代码-我只是创建了一个点并重载了+和-运算符,它们都作为类的成员和全局函数。
但是,当我编译此代码时,我发现虽然(2)有效,但(1)和(3)都继续显示错误,我看不出为什么:
q1.cpp:17:10:错误:没有匹配的构造函数来初始化'Point'返回Point(x-p2.x,y-p2.y); ^ ~~~~~~~~~~~~~~~~~~~~ q1.cpp:8:2:注意:候选构造函数不可行:第一个参数从'Point'到'int'的未知转换
据我了解,(1)和(3)均应返回一个临时Point对象,根据Google搜索,该对象应与情况(2)等效。
另外,错误语句使我更加困惑-我看不到在表达式中发生的任何转换都是有问题的。
Point(x-p2.x, y-p2.y).showLocation();
这很好用,情况(2)也可以,所以我想这不是语法问题。 除了返回临时对象(未命名)的问题的可能性之外,我看不到其他任何问题。
谢谢!
您可以通过简单地删除复制构造函数来解决此问题。 它没有任何用处。 或者,您可以根据默认签名在签名中使用const
来修复副本构造const
。
Point(Point const & copy) : x(copy.x), y(copy.y) { }
如果没有const
,则复制构造函数不能与临时实例一起用作输入。
资源:
这个:
Point(Point& copy) : x(copy.x), y(copy.y) { }
是技术上有效的副本构造函数 ,但它限制了可能的实际参数。
临时或const
对象不能绑定到Point&
形式参数,因为这是对非const
的引用,这将允许修改实际参数。
相反,你可以写
Point( Point const& other ): x( other.x ), y( other.y ) {}
在此我还纠正了误导性参数命名的问题。
但更简单的是,对于本课程,您可以
Point( Point const& other ) = default;
绝对最简单,就是根本不定义一个复制构造函数,让编译器为您完成。
同样,为了获得最大的可用性,您应该更改
Point operator-(Point& p2) { // (1)
至
Point operator-(Point const& p2) const { // (1)
参数的const
表示现在可以使用const
或临时(右值)参数调用它。
和const
的成员函数本身,最后一个const
,意味着它可以在一个被称为const
对象。 这里的规则有些微妙。 与参数的限制相反,如果没有const
则可以在临时对象上调用它(即通过rvalue-expression)。
一般建议:
在几乎可以使用的任何地方自由地散布const
,
让编译器生成复制操作, 除非您负责复制 ,并且
优先使用安全复制类型的数据成员,例如内置类型,智能指针和标准库集合。
错误的原因(在您的情况下为(1))是
Point operator-(Point& p2) { // (1)
Point(x-p2.x, y-p2.y).showLocation();
return Point(x-p2.x, y-p2.y);
}
是Point(x-p2.x, y - p2.y)
产生一个临时对象。 返回(语义上)需要创建临时副本,这需要接受const
参数的副本构造const
。 您的副本构造函数不接受const
参数。
解决方案是修改您的副本构造函数以接受const
参数,或者将其彻底删除(因为编译器会自动生成一个对您而言正确工作的副本构造函数)。 在C ++ 11中,使用Point(const Point &) = default;
如果需要,可以强制编译器生成正确的副本构造函数。
注意:该标准要求编译器强制执行对正确的副本构造函数的需求,即使临时文件已被优化为不存在也是如此。 这有助于提高代码对未优化临时文件的编译器的可移植性。
代码的另一个问题是您有两种operator-()
变体。
您的情况(1)和(3)不相等。 第一个生成operator-()
的成员函数形式(接受一个参数,因为有一个隐含this
),第二个生成的非成员形式接受两个参数。
当它看到一个类似p1-p2
的表达式(其中p1
和p2
都是Point
类型)时,该operator-()
两个版本都是不错的候选者。 编译器会抱怨模棱两可,因为没有理由比另一个更偏爱一个。 所以一个声明
(p1-p2).showLocation();
将无法编译。 我认为您是出于这个原因将其注释掉了。
解决方案是使用operator-()
一种形式或另一种形式。 不能一次全部。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.