Reputation: 2300
i need to implement an isEqual method to multiple objects that are have multiple levels of inheritance. For this reason i have decided to create not a interface since the method are not pure virtual but just a class that i can use later as a tag.
Those classes implement a single method isEqual. Since i need a default behavior defined those methods are not pure virtual.
class A_Interface {
virtual isEqual(shared_ptr<A_Interface> obj);
...
virtual otherMethod1();
}
class B_Interface : public virtual A_Interface {
virtual isEqual(shared_ptr<B_Interface> obj);
...
virtual otherMethod2();
}
class C_Interface : public virtual B_Interface {
virtual isEqual(shared_ptr<C_Interface> obj);
...
virtual otherMethod3();
}
each class implements it's own "interface like" tag class mentioned above and inherits from the parent like this:
class A : public virtual A_interface;
{
isEqual(shared_ptr<A_Interface> obj){
...
}
};
class B : public virtual A,
public virtual B_interface
{
using A::isEqual;
isEqual(shared_ptr<B_Interface> obj){
...
}
};
class C : public virtual B,
public virtual C_interface
{
using B::isEqual;
isEqual(shared_ptr<C_Interface> obj){
...
bool parentIsEquals = B::isEqual(obj);
...
}
};
In order to avoid name hinding in Class B i explicitelly declared the
using A::isEqual;
statement which solved the problem but now in class C when i want to reffer to the method "isEqual" parent class B and explicitelly specifing it like that
bool parentIsEquals = B::isEqual(obj);
i get the error
"B::isEqual' is ambiguous"
which I also understand since i have two signatures i.e.
using A::isEqual;
isEqual(shared_ptr<B_Interface> obj);
what i do not know is how to address this issue since the argument in this case "obj" does match bought signatures. I would like to understand if there a better pattern/proposition of implementing this problem.
Upvotes: 0
Views: 88
Reputation: 40070
Keep it simple.
With the following class hierarchy:
struct A { int value1; };
struct B : A { int value2; };
struct C : B { int value3; };
You can define equality operators for A
s, B
s and C
s
bool operator==(A const& lhs, A const& rhs)
{
return lhs.value1 == rhs->value1;
}
bool operator==(B const& lhs, B const& rhs)
{
return lhs.value2 == rhs->value2
&& static_cast<A const&>(lhs) == static_cast<A const&>(rhs);
}
bool operator==(C const& lhs, C const& rhs)
{
return lhs.value3 == rhs->value3
&& static_cast<B const&>(lhs) == static_cast<B const&>(rhs);
}
With it, a bit of sugar:
template<class Wrapper>
bool operator==(A const& lhs, Wrapper const& rhs)
{ return lhs == *rhs; }
template<class Wrapper>
bool operator==(Wrapper const& rhs, A const& lhs)
{ return rhs == lhs; }
// and so on...
All those simple functions allow you a great deal of flexibility:
B b1{{1}, 2};
auto c2 = std::make_unique<C>(C{{{1}, 2}, 3});
bool const equals = b1 == c2; // true
Upvotes: 1