重载运算符以允许 C++ 中参数的不同顺序

Overloading an operator to allow different order of parameters in C++

假设我正在编写 class 来表示计算机图形应用程序的 3D 矢量。我希望能够将向量乘以标量,如下所示:

Vector3D vec(1, 2, 3);  // The paramaters of the constructor are the x, y and z values
Vector3D vec1 = vec * 2; // Case A: result should be (2, 4, 6)
Vector3D vec2 = 2 * vec; // Case B: result should be (2, 4, 6)

为了使案例 A 有效,我可以将以下函数添加到我的 class:

class Vector3D
{
public:
    // ...
    const Vector operator*(int scalar) const;
};

为了使案例 B 工作,我必须在 class:

之外创建一个函数
const Vector operator*(int scalar, const Vector& vec);

请注意,我还可以通过在 class 之外添加以下函数来使案例 A 工作:

const Vector operator*(const Vector& vec, int scalar);

我的问题是:最干净的方法是什么?我可以在我的 class 中添加一个函数,在它之外添加一个函数,或者我可以在我的 class 之外添加两个函数。我喜欢在 class 之外添加两个函数的想法,因为我可以让它们彼此相邻,我认为这更清楚,因为它们本质上做同样的事情,但确实在 [= 内部添加了一个函数27=] 有什么我没有看到的好处吗?

请注意,我的函数的 return 值是常量,因此用户无法这样做(如 Scott Meyers 在他的 Effective C++ 一书中所解释的):

Vector3D vecA(1, 2, 3);
Vector3D vecB(1, 2, 3);
Vector3D vecC(1, 2, 3);

vecA * vecB = vecC;

由于向量乘以标量是对称的,在没有明确的 "superior" 或 "subordinate" 参与者的意义上,我会使用一对独立的运算符重载:

const Vector operator*(int scalar, const Vector& vec);
const Vector operator*(const Vector& vec, int scalar);

当您在重载成员函数和重载独立函数之间做出选择时,应该根据对象本身参与函数参数的计算来做出决定。

当对象起中心作用,而参数起外围作用时,通过使对象成为成员来保持对象的功能。当对象和函数参数起着相似的作用时,即参与者之间存在一定程度的对称性时,独立函数更合适。

通常的做法是提供 operator *=(int) 作为成员函数,然后编写调用它的自由函数 operator*(Vector3D, int)operator*(int, Vector3D)

这里的 operator* 是对称的(如 a * bb * a 应该是等效的操作)所以你应该更喜欢在 class 之外拥有这两个功能.

除了您提到的 - 让它们彼此靠近可以使它更清晰 - 它还允许对任一操作数进行隐式转换。另一方面,如果 Case A 的 operator* 是成员函数,则不允许将左侧操作数隐式转换为 Vector3D 类型,但不允许将右侧操作数转换为 Vector3D 类型是允许的(除非你标记构造函数 explicit,但这不是重点)。

通过使用孪生非成员函数,我们实现了真正的对称性,因为两个操作数都具有相同的转换为 Vector3D 类型的能力。

顺便说一下,C++ Core Guidelines written by Bjarne Stroustrup and Herb Sutter 也建议这样做。