我正在写一个Point类,它包含三个浮点数,x y z,一些函数和重载运算符。我用以下形式编写了运算符:
inline Point Point::operator+ (Point point)
{
return Point(x + point.x, y + point.y, z + point.z);
}
inline void Point::operator+= (Point point)
{
x += point.x;
y += point.y;
z += point.z;
}
这是重载这些运算符的正确方法吗?我已经测试了它并且它有效但我已经看到了另一种形式:
inline Point& Point::operator+ (Point& point)
{
return Point(x + point.x, y + point.y, z + point.z);
}
inline Point& Point::operator+= (Point& point)
{
x += point.x;
y += point.y;
z += point.z;
return *this;
}
这两种形式有什么区别?
此外,我可以使用我的Point.cpp文件中的运算符,但如果我尝试使用它在Main.cpp中说,我得到一个未解析的外部符号的lnk2019错误。奇怪的是,我的函数在定义文件之外工作。为了让这些操作符在他们定义的文件之外工作,我缺少什么?
答案 0 :(得分:3)
第一个操作符应该是
inline Point Point::operator+ (const Point &point) const
{
return Point(x + point.x, y + point.y, z + point.z);
}
它不应该返回引用,因为它除了构造一个新对象而不修改现有对象(一般的经验法则)。 const被添加到函数中,因为不应该修改它所调用的点。添加对点作为参数的引用,因此不会有不必要的副本
第二个应该是
inline Point& Point::operator+= (const Point& point)
{
x += point.x;
y += point.y;
z += point.z;
return *this;
}
因为它应该修改现有的点,所以它应该返回一个引用。 const被添加到参数中,因为它不应该被更改。函数本身不是const,因为它应该修改点本身。
您获得的链接器错误是因为内联。要么在头文件中提供完整的实现,要么删除内联。
答案 1 :(得分:2)
inline Point& Point::operator+ (Point& point)
{
return Point(x + point.x, y + point.y, z + point.z);
}
这是错误的,它返回对函数返回时不再存在的临时引用的引用。如果你足够幸运,它会导致段错误。如果您尝试这样做,大多数编译器会给您一个警告。理想情况下,您可以将此运算符编写为自由函数,并根据您的成员operator+=
实现。
inline Point& Point::operator+= (Point& point)
{
x += point.x;
y += point.y;
z += point.z;
return *this;
}
这几乎是首选方式,除了你应该将point
作为const引用,否则你不能将它与temporaries一起使用。返回对自身的引用是允许链接运算符的原因。人们普遍认为,如果有疑问,可以像彗星那样做,并且贪婪地这样做。
总结一下,'cannonical'实现将是:
inline Point& Point::operator+=( Point const& point )
{
x += point.x;
y += point.y;
z += point.z;
return *this;
}
inline Point const operator+( Point left, Point const& right )
{
return left += right;
}
请注意,operator+
是一个自由函数,允许Point
转换到两个操作数,而不仅仅是正确的操作数。它方便地用operator+=
实现:左边的参数是按值获取的,以便有一个我们可以修改的临时副本,我们通过向它添加正确的参数来实现。由于operator+=
返回一个引用,我们使用这样的返回来提供将作为函数结果复制的值。