我很难形成一个我想问的问题,所以让我举个例子:
假设我们正在开发一个3d系统,我们已经定义了一个矢量类Vec3。我们重载一些算术运算符以获得明显的重复。其中我们重载*运算符,以便它返回两个向量的点积。现在我们的代码应该是这样的:
class Vec3{
private:
float x, y, z;
public:
float operator*(const Vec3&) const; //dot product
.
.
.
现在说我们希望能够通过使用带有某些东西的*运算符来缩放我们的向量,比如浮点数。这可以通过声明以下内容来完成:
Vec3 operator*(const float) const;
friend Vec3 operator*(const float, const Vec3&);
这有两个超载和我想知道是否有办法只用一个,即我们声明这而不是上面两行:
friend Vec3 operator*(const Vec3&, const Vec3&);
然后为Vec3 ctor添加默认值以处理来自float的转换。
最后一个例子适用于:
Vec3 someVec3 = 1.0 * otherVec3; //through friend Vec3 operator*(const float, const Vec3&)
然而不是这样:
Vec3 someVec3 = otherVec3 * 1.0;
因为编译器不知道要使用哪两个:
friend Vec3 operator*(const float, const Vec3&); //the one we want to use
or
float operator*(const Vec3&) const; //the one for the dot product
有什么建议吗?
谢谢!
答案 0 :(得分:5)
在这种情况下,我最初建议不要对运算符进行重载,因为您的用户如何知道*
是否代表点或交叉产品(两者都是合理的含义,具体取决于客户的预期用途)。我实际上建议不要支持operator*
并使用dot
,cross
和scale
成员进行支持。然后,您不必担心多次重载,并且您的用户可以清楚地知道他们正在获得什么。
但是如果你想继续使用运算符,那么有两个重载是没有错的。创建一个虚拟Vec3
进行缩放不仅在语义上不正确,而且会增加少量不必要的开销。
答案 1 :(得分:2)
Boost.Operators可以为您完成大部分的锅炉工作。 E.g:
class Vec3
: boost::multipliable2<Vec3, float>
{
public:
// ...
Vec3 operator*=(float);
// Vec3 operator*(Vec3, const float&) and
// Vec3 operator*(const float&, Vec3) auto-generated
// by multipliable.
};
答案 2 :(得分:1)
在几个重载中没有任何错误,特别是如果它们可以很容易地相互实现的话,那就不会出现错误:
Vec3 operator*(const float scale, const Vec3& vec)
{ return vec * scale; }
很难让它变得简单!