6

我正在学习 C++,我想知道是否可以深入了解创建适用于两种不同类型实例的二元运算符的首选方法。这是我为说明我的担忧而做的一个例子:

class A;
class B;

class A
{
    private:
        int x;

    public:
        A(int x);

        int getX() const;

        int operator + (const B& b);
};


class B
{
    private:
        int x;

    public:
        B(int x);

        int getX() const;

        int operator + (const A& A);
};


A::A(int x) : x(x) {}

int A::getX() const { return x; }

// Method 1
int A::operator + (const B& b) { return getX() + b.getX(); }


B::B(int x) : x(x) {}

int B::getX() const { return x; }

// Method 1
int B::operator + (const A& a) { return getX() + a.getX(); }


// Method 2
int operator + (const A& a, const B& b) { return a.getX() + b.getX(); }

int operator + (const B& b, const A& a) { return a.getX() + b.getX(); }


#include <iostream>

using namespace std;

int main()
{
    A a(2);
    B b(2);

    cout << a + b << endl;

    return 0;
};

如果我想在这两种类型之间具有对称性,那么在上面的代码中哪种方法是最好的方法。选择一种方法而不是另一种方法是否有任何可能的危险?这是否因返回类型而异?请解释!谢谢!

4

4 回答 4

10

最好的方法是定义(在任一类之外)int operator+ (const A& a, const B& b),并在需要时使其成为两个类的友元函数。此外,定义

int operator+(const B& b, const A& a) {return a + b;}

使其对称。

于 2009-03-31T19:28:10.470 回答
4

这种方法的最大风险是人们倾向于将 + 视为对称运算符。这是写的方式,它不是(除非你的实现是相同的)。

至少,您应该将 + 作为外部二元运算符(而不是成员)重载,然后多次重载它。

但是,您必须小心,以确保没有任何事情变得模棱两可。

你能解释一下你想做什么吗?我想不出有很多不同类型的情况下,拥有对称异构运算符是有意义的。

于 2009-03-31T19:26:31.020 回答
1

方法 2 的主要论点是您可以在两个操作数上进行隐式类型转换,而不仅仅是第二个。这可能会在某个地方避免混乱。

说到这一点,您的示例代码通过两个类上的 1-arg 构造函数定义了从 int 到 A 和从 int 到 B 的隐式转换。这可能会导致以后产生歧义。但是,如果您为了简洁而省略了“显式”,那就足够了。

不过,我同意 Uri 的警告:如果您发现自己这样做,您可能正在编写一个其他人会感到困惑的 API。为什么 A 加 B 是 int ?添加 a 和 b,而不是自己调用 getX 并添加结果,真的让用户更容易吗?

是因为用户非常清楚 A 和 B 是整数的包装器吗?如果是这样,那么另一种选择是通过运算符 int() 公开从 A 到 int 和从 B 到 int 的转换。然后 a+b 将出于合理的原因返回一个 int ,并且您还将获得所有其他算术运算符:

#include <iostream>

struct A {
    int x;
    explicit A(int _x) : x(_x) {}
    operator int() {
        return x;
    }
};

struct B {
    int x;
    explicit B(int _x) : x(_x) {}
    operator int() {
        return x;
    }
};

int main() {
    A a(2);
    B b(2);
    std::cout << a + b << "\n";
    std::cout << a - b << "\n";
}
于 2009-03-31T19:38:57.183 回答
1

我在评论中读到您的预期用途是添加向量和矩阵。也许你应该考虑只使用向量是一维矩阵的矩阵。然后你只剩下一种类型和一组运算符:

matrix operator*( matrix const& a, matrix const& b );
matrix operator+( matrix const& a, matrix const& b ); // and so on

如果要保留向量类,则应考虑是否还需要转置向量(也许转置只是向量的内部属性)。

这组操作并不是真正对称的:

vector * matrix = vector
matrix * vector_t = vector_t
matrix * matrix = matrix
vector_t * vector = matrix
vector * vector_t = int

并且您应该提供这三个操作(假设转置是向量的属性):

vector operator*( vector const& v, matrix const& m );
vector operator*( matrix const& m, vector const& v );
matrix operator*( matrix const& m1, matrix const& m2 );
matrix operator*( vector const& v1, vector const& v2 ); // possibly 1x1 matrix, you cannot overload changing only return value

如果可能,所有功能都是免费的。即使上面的集合不是对称的,现实世界也不是对称的,你的用户会期望它。

于 2009-04-01T06:23:39.147 回答