我有一个基类并在其上定义了一个运算符==。 B
是A
的子类,我忘了在operator==
上定义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
答案 0 :(得分: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
答案 1 :(得分:3)
允许对greatwolf的精彩approach进行隐式转换有点棘手:
#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;
}
答案 2 :(得分:1)
为什么在类层次结构中进行相等比较?在许多情况下,这表明设计存在问题,类的行为不像值类型,但不像层次结构中的对象那样。