你能避免数学运算符的多个运算符重载吗?

Can you Avoid Multiple Operator Overloads for Mathematical Operators?

假设我有一个非常简单的 Rational class,如下所示:

class Rational
{

    int numer;
    int denom;

public:

    Rational(const int& numer, const int& denom) : numer(numer), denom(denom) {}
    void operator*(const Rational& other) { std::cout << "multiply, simple as\n"; }
}

一切都很好。然后说我希望能够将我的 Rational class 乘以一个整数,所以我在 class:

中添加了另一个函数
class Rational
{
    
    int numer;
    int denom;
    
public:
    
    Rational(const int& numer, const int& denom) : numer(numer), denom(denom) {}
    void operator*(const Rational& other) { std::cout << "multiply, simple as\n"; }
    void operator*(const int& other) { std::cout << "some math here\n"; }
}

好的,没什么大不了的。除了我实际上不能执行以下操作,因为参数的顺序都是错误的:

Rational mine(1, 2);
const Rational result = 2 * mine;

好的,再进行一次迭代,我得到以下结果:

class Rational
{
    
    int numer;
    int denom;
    
public:
    
    Rational(const int& numer, const int& denom) : numer(numer), denom(denom) {}
    void operator*(const Rational& other) { std::cout << "multiply, simple as\n"; }
    void operator*(const int& other) { std::cout << "some math here\n"; }
    friend void operator*(const int& other, const Rational& mine) { std::cout << "even more math here\n"; }
}

我想知道的是,是否有一种方法可以避免为我希望 class 支持的每个数学运算编写相同的函数两次,这样就可以了我可以按我想要的任何顺序用参数调用它。这很可能就是您必须在 C++ 的类型系统中实现此类事情的方式,但是必须为您希望 class 支持的每个数学运算添加此样板似乎有点烦人。

单一函数的问题在于 * 左右操作数的类型会有所不同(您必须以不同的方式使用它们)。

这可以通过将两个参数类型固定为 Rational 并创建从 int xRational x/1 的隐式转换来解决(无论如何这可能是可取的)。这样,在 2 * mine 中,2 将隐式转换为 Rational(2, 1) * mine.

这是一个例子:

class Rational
{

    int numer;
    int denom;

public:
    // default argument of denom=1 allows implicit conversion from int
    Rational(int numer, int denom = 1) : numer(numer), denom(denom) {}
    friend Rational operator*(const Rational& l, const Rational& r) {
        std::cout << "Rational(" << l.numer << ", " << l.denom
              << ") * Rational(" << r.numer << ", " << r.denom << ")\n";
        // calculate and return result
    }
    friend Rational operator/(const Rational& l, const Rational& r) { /* ... */ }
    friend bool operator==(const Rational& l, const Rational& r) { /* ... */ }
};