4

我有一个基类并在其上定义了 operator== 。AndB是 的子类,A我忘了定义operator==on B。然后A::operator==用于比较B,通常这会产生意想不到的结果。有什么好的方法可以避免这种“忘记”吗?我添加一个例子来澄清我的问题。

class A
{
public:
    bool operator==(const A& rhs) const
    {
        return i == rhs.i;
    }

    int i
};

class B : public A
{
public:
    int j;
}

B b1, b2;
b1.i = 1; b1.j = 2;
b2.i = 1; b1.j = 3;
bool b = (b1 == b2); // will be true
4

3 回答 3

5

您可以尝试将其放入A命名空间中,在该命名空间中创建operator ==模板非成员并让 ADL 处理它。

#include <iostream>

namespace stuff {
class A
{
};

class B : public A {};

template <typename T>
bool operator == (const T &lhs, const T &rhs)
{
  std::cout << __PRETTY_FUNCTION__ << '\n';
  return &lhs == &rhs; // <-- replace this with something real
}

}

struct C {};

int main()
{
  stuff::A a, aa;
  stuff::B b, bb;
  C c, cc;

  b == bb;
  aa == a;

  aa == cc; // error: no match for "operator==" stuff::A and C
  b == a;   // error: no match for "operator==" stuff::B and stuff::A
}

编辑:对于您希望相等性检查将类的每个部分与其他相应部分进行比较的编辑示例,DyP 的建议可以工作。例如:

// same as before
// ...
class A
{
public:
  bool is_equal(const A &rhs) const { return i == rhs.i; }
};

class B : public A
{
public:
  bool is_equal(const B &rhs) const { return A::is_equal(rhs) && (j == rhs.j); }
};

template <typename T>
bool operator == (const T &lhs, const T &rhs)
{
  std::cout << __PRETTY_FUNCTION__ << '\n';
  return lhs.is_equal(rhs);
}

现在在使用代码中再次比较:

// ...
b.i = 1, bb.i = 1;
b.j = 1, bb.j = 42;
cout << boolalpha << (b == bb) << '\n';
b.j = 42;
cout << (b == bb) << '\n';

a.i = 2, aa.i = 3;
cout << (aa == a) << '\n';    

输出:

bool stuff::operator==(const T&, const T&) [with T = stuff::B]
false
bool stuff::operator==(const T&, const T&) [with T = stuff::B]
true
bool stuff::operator==(const T&, const T&) [with T = stuff::A]
false
于 2013-09-13T03:28:21.807 回答
3

允许为greatwolf的伟大方法进行隐式转换有点棘手:

#include <type_traits>

namespace stuff
{

    template<class T, class U>
    bool operator== (const T &lhs, const U &rhs)
    {
        using namespace std;
        static_assert(is_convertible<T, U>{} || is_convertible<U, T>{},
                      "invalid argument type");
        static_assert
        (
               is_same<T, U>{}
            || ( not is_base_of<T, U>{} && not is_base_of<U, T>{})
            , "use explicit casts to compare derived to base class types"
        );
        return is_equal(lhs, rhs);
    }

    template<class T>
    bool is_equal(T const&, T const&)
    {
        // force compile-time failure when instantiating
        static_assert(std::is_same<T, void>{},
          "no free is_equal function for these argument types available");

        return false;
    }

    class A
    {
    private:
        int i;

        friend bool is_equal(A const& lhs, A const& rhs)
        { return lhs.i == rhs.i; }

    public:
        A(int p_i) : i(p_i) {}
    };

    class B : public A
    {
        int j;

    public:
        B(int p_i, int p_j) : A(p_i), j(p_j) {}
    };

    class C : public A
    {
    private:
        int j;

        friend bool is_equal(C const& lhs, C const& rhs)
        {
            return    is_equal(static_cast<A const&>(rhs),
                               static_cast<A const&>(lhs))
                   && lhs.j == rhs.j;
        }

    public:
        C(int p_i, int p_j) : A(p_i), j(p_j) {}
    };

}

struct D
{
    operator stuff::C() const
    {
        return stuff::C(1, 42);
    }
};

#include <iostream>
int main()
{
    stuff::A a(1), aa(1);
    stuff::B b(1, 42), bb(1, 42);
    stuff::C c(1, 42), cc(1, 42);

    D d;

    // commented lines invoke compilation failures
    std::cout << "a == aa: " << (a == aa) << std::endl;
  //std::cout << "a == b : " << (a == b ) << std::endl;
  //std::cout << "b == bb: " << (b == bb) << std::endl;
  //std::cout << "a == c : " << (a == c ) << std::endl;
    std::cout << "c == cc: " << (c == cc) << std::endl;
    std::cout << "d == c : " << (d == c ) << std::endl;
}
于 2013-09-13T04:10:26.270 回答
1

为什么在类层次结构中进行相等比较?在许多情况下,这表明设计存在问题,即类的行为不像值类型,但也不像层次结构中的对象。

于 2013-09-13T14:24:28.027 回答