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.
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 As, Bs and Cs
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
Related
This question is a follow up on Here. The goal was to implement a virtual equal operator between non templated classes. In this question, I am asking for the same goal for a templated class.
#define EQUAL_FOR_BASE(derived) virtual bool equal(const derived& eq) const { return false; };
#define EQUAL_FOR_DERIVED(this_derived) bool equal(const Equalable& equalable) const { return equalable.equal(*this_derived); };
class RandomClass; //This is for clarification purposes, not used.
class DerivedTemplateType_One;
class DerivedTemplateType_Two;
class Equalable
{
public:
Equalable() = default;
virtual ~Equalable() = default;
virtual bool operator==(const Equalable& eq) { return this->equal(eq); };
EQUAL_FOR_BASE(RandomClass);
EQUAL_FOR_BASE(DerivedTemplateType_One);
EQUAL_FOR_BASE(DerivedTemplateType_Two);
virtual bool equal(const Equalable& eq) const = 0;
};
class RandomClass : public Equalable
{
public:
RandomClass() = default;
~RandomClass() = default;
EQUAL_FOR_DERIVED(this);
virtual bool equal(const RandomClass& rc) const { return m_double == rc.m_double; };
double m_double;
};
class TemplateType : public Equalable //Still pure virtual due to equal in Equalable.
{
public:
TemplateType() = default;
virtual ~TemplateType() = default;
int m_string;
};
class DerivedTemplateType_One : public TemplateType
{
public:
EQUAL_FOR_DERIVED(this);
virtual bool equal(const DerivedTemplateType_One& one) const { return m_int == one.m_int; };
int m_int;
};
class DerivedTemplateType_Two : public TemplateType
{
public:
EQUAL_FOR_DERIVED(this);
virtual bool equal(const DerivedTemplateType_Two& two) const { return m_size == two.m_size; };
std::size_t m_size;
};
template<typename T>
class Target : Equalable
{
public:
T m_t;
};
Q1: I want to limit the template typename T above to be a derived class of TemplateType (derived from Equalable) e.g. Can be DerivedTemplateType_One/Two (Of course there will be Three, Four..)? Isn't there static_assert or some metaprogramming to check this at compile time or would:
template<TemplateType DerivedTypeOneOrTwo>
class Target : public Equalable
{
public:
DerivedTypeOneOrTwo m_t;
};
Work?
Q2: How can I implement the equal operator as I did for RandomClass please?
Q3: I am asking about Q1 in order to limit template types possible so that Q2 is possible, can I generalize Q1: Limit template typename T to classes inheriting from Equalable (instead of TemplateType ) and still do Q2?
Sorry this is getting a bit complicated but there is no easy way :) Thanks very much!!
Ps: I am making everything public to save space, please ignore.
I ended using CRTP if anyone is interested (Please let me know if I am doing something wrong I missed)
template<class Derived>
class Equalable
{
public:
using derived_type = Derived;
bool operator==(const Derived& derived) const { return this->equal(derived); };
bool operator!=(const Derived& derived) const { return !(*this == derived); }
private:
virtual bool equal(const Derived& derived) const = 0;
};
class B : public Equalable<B>
{
public:
B(double d) : m_example(d) {};
private:
virtual bool equal(const B& derived) const override { return derived.m_example == m_example; };
double m_example;
};
class A : public Equalable<A>
{
public:
A(std::string d) : m_example(d) {};
private:
virtual bool equal(const A& derived) const override { return derived.m_example == m_example; };
std::string m_example;
};
Now we can compare element of same type:
int main()
{
A a("string");
B b(1);
A aa("other_string");
B bb(11);
std::cout << (a == aa) << std::endl; //Ok
std::cout << (b == bb) << std::endl; //Ok
std::cout << (a == b) << std::endl; //Wrong, not supported.
};
I tried doing this:
template<class A, class B>
static bool equal(const Equalable<A>& a, const Equalable<B>& b)
{
if (!std::is_same<A, B>::value)
return false;
return a == b;
};
But didn't compile, so I just used equality between same types.
To limit template (As of Question Q1) there a standard check:
static_assert(std::is_base_of<Base, Derived>::value, "Only from Base");
Hope you have better suggestions, I still don't like this :) Thanks everyone!
Given the following excerpts:
class Interface {
public:
virtual bool operator==(const Interface &other) const = 0;
virtual void print(ostream& sout) const = 0;
};
class A : virtual public Interface {
public:
virtual bool operator==(const Interface &other)const;
virtual void print(ostream& sout)const;
protected:
short m_foo;
};
class B : virtual public Interface {
public:
virtual bool operator==(const Interface &other)const;
virtual void print(ostream& sout) const;
protected:
short m_bar;
};
class C: public A, public B {
public:
virtual bool operator==(const Interface &other) const;
virtual void print(ostream& sout) const;
};
In C.cpp I'm trying to implement operator==:
bool C::operator==(const Interface &other) const {
try {
// This works, but it's duplicating code from A.cpp and B.cpp
const C& otherC = dynamic_cast<const C&>(other);
return (m_foo == otherC.m_foo && m_bar == otherC.m_bar);
// This doesn't work -- it calls C::operator== instead of
// A::operator== and B::operator== (infinite recursion).
/*
return (dynamic_cast<const A&>(*this) ==
dynamic_cast<const A&>(other) &&
dynamic_cast<const B&>(*this) ==
dynamic_cast<const B&>(other));
*/
} catch (bad_cast e) {
return false;
}
}
I can get it to work for the output method, but I don't know how to do
something equivalent when overriding operators:
void C::print(ostream& sout) const {
A::print(sout);
sout << " ";
B::print(sout);
}
Is there a way to call the base classes' virtual operators instead of doing
something like adding a virtual equals() method and just having operator== call
that?
(Note: this code is based off of a small part of a homework assignment in case
that's relevant.)
You need to explicitly name the operator you want to use.
Replace:
return (dynamic_cast<const A&>(*this) ==
dynamic_cast<const A&>(other) &&
dynamic_cast<const B&>(*this) ==
dynamic_cast<const B&>(other));
With Edit: corrected
return (A::operator==( other ) &&
B::operator==( other ));
return A::operator==(other) && B::operator==(other);
The two base classes should handle any type error in other, so you don't need to do anything about that here.
EDIT: rewrote code to use explicit call.
Consider the following abstract class:
class Abstract {
public:
// ...
virtual bool operator==(const Abstract& rhs) const = 0;
// ...
};
Now suppose I'm creating multiple derived classes from this abstract class. However, each one uses a different algorithm when comparing with its own type, and a generic algorithm when comparing with any of the other derived classes. Between the following two options, which would be the better, more efficient option?
Option A:
class Derived : public Abstract {
public:
// ...
bool operator==(const Abstract& rhs) const {
// Code for comparing to any of the other derived classes
}
bool operator==(const Derived& rhs) const {
// Code for comparing to myself
}
// ...
};
Option B:
class Derived : public Abstract {
public:
// ...
bool operator==(const Abstract& rhs) const {
const Derived* tmp = dynamic_cast<const Derived*>(&rhs);
if (tmp) {
// Code for comparing to myself
}
else {
// Code for comparing to any of the other derived class
}
}
};
I'm really curious as to what advantages and disadvantages these options would have, as C++ typecasting is a relatively mysterious topic to me. Furthermore, which solution is more "standard", and does the second solution have any impacts on performance?
Is there possibly a third solution? Especially if there were many derived classes, each needing its own special comparison algorithm against different derived classes?
Your two methods are for different situation. For option A, the static type of rhs is used to decide which function to call, and for option B the dynamic type is used.
So if you want your program to choose its behavior base on the "real" type of the argument, I think you should choose the second option. If types can be known at compile time, option A should be used since it gives better performance.
I think that option B is what you are looking for if you're expecting the == operator to use the dynamic type of the argument. For example:
class base
{
public:
virtual bool operator ==( const base& other ) = 0;
};
class derived : public base
{
public:
bool operator ==( const base& other ) { return false; }
bool operator ==( const derived& other ) { return true; }
};
int main()
{
base* a = new derived;
base* b = new derived;
std::cout << ( *a == *b ) << std::endl;
}
This prints:
0
So operator ==( const base& other ) gets called, even if the actual dynamic type is derived.
You actually can do it third way using one of the techiniques to implement double dispatching. This approach is fully described in Item 31 of "More Effective C++". Here is small example:
#include <iostream>
class Derived1;
class Derived2;
class Base
{
public:
virtual bool operator==( Base& other) = 0;
virtual bool compare( Base& other) {return false;}
virtual bool compare( Derived1& other) {return false;}
virtual bool compare( Derived2& other) {return false;}
};
class Derived1 : public Base
{
public:
virtual bool operator==( Base& other) {return other.compare(*this);}
virtual bool compare( Base& other) {return false;}
virtual bool compare( Derived1& other) {return true;}
};
class Derived2 : public Base
{
public:
virtual bool operator==( Base& other) {return other.compare(*this);}
virtual bool compare( Base& other) {return false;}
virtual bool compare( Derived2& other) {return true;}
};
int main()
{
Base *a = new Derived1;
Base *b = new Derived1;
Base *c = new Derived2;
std::cout << (*a == *b) << std::endl;
std::cout << (*a == *c) << std::endl;
return 0;
}
Output:
1
0
Unfortunately C++ have no multimethods that would choose the current function to call based on dynamic type information. You need double dispatch, visitor pattern or some other trick to implement the behavior.
i am a new programer in c++
and i have an abstract class A, and i implemented operators in it.
and now i have two classes B and C that extend A.
for some reason the compiler does not identify the operators.
is it because that operators are not inherrited? or is it because that i have a code bug?
here is the code:
#ifndef A_
#define A_
class A{
public:
friend bool operator==(const A &a1,const A &a2);
}
#endif
inline bool operator==(const A& a1, const A& a2){
....
}
is it not meant to work on B==C and B==B and C==C?
thanx
Matt
The program compiles and runs as expected, correctly calling the right operator when I try it:
class A {
public:
friend bool operator==(const A &a1, const A &a2);
};
bool operator==(const A &a1, const A &a2) {
return false;
}
class B : public A {};
class C : public A {};
int main()
{
B b;
C c;
bool equals = b == c;
return 0;
}
Put the operator inside the class.
#ifndef A_
#define A_
class A
{
...
public:
bool operator==(const A &other)
{
// your operator logic
}
}
#endif
Optionally, you could make it virtual thus allowing you to override it in the derived classes.
My suggestion: don't overload comparison operators in base classes, but implement equivalent protected methods. This will prevent some hard to detect failures in your program.
Example:
class Base
{
protected:
bool equal_base(const Base& other) const
{ return member == other.member;}
private:
unsigned int member;
};
class B_Child : public Base
{
public:
bool operator==(const B_Child& other) const
{ return (member_b == other_member_b) && equal_base(other);}
private:
std::string member_b;
};
class C_Child : public Base
{
public:
bool operator==(const C_Child& other) const
{ return (member_c == other_member_c) && equal_base(other);}
private:
double member_c;
};
Also search the web for "C++ virtual equality operator".
How about:
class A
{
public:
bool operator==(A const& rhs) const
{
return this->isEqual(rhs);
}
private:
virtual bool isEqual(A const& rhS)
{
return /* Your test here */
}
};
class B: public A
{
private:
virtual bool isEqual(A const& rhS)
{
B& theRealRHS = dynamic_cast<B const&>(rhs); // Throws if it is not a B
return /* Your test here */
}
};
Suppose I have the following class hierarchy:
class A
{
int foo;
virtual ~A() = 0;
};
A::~A() {}
class B : public A
{
int bar;
};
class C : public A
{
int baz;
};
What's the right way to overload operator== for these classes? If I make them all free functions, then B and C can't leverage A's version without casting. It would also prevent someone from doing a deep comparison having only references to A. If I make them virtual member functions, then a derived version might look like this:
bool B::operator==(const A& rhs) const
{
const B* ptr = dynamic_cast<const B*>(&rhs);
if (ptr != 0) {
return (bar == ptr->bar) && (A::operator==(*this, rhs));
}
else {
return false;
}
}
Again, I still have to cast (and it feels wrong). Is there a preferred way to do this?
Update:
There are only two answers so far, but it looks like the right way is analogous to the assignment operator:
Make non-leaf classes abstract
Protected non-virtual in the non-leaf classes
Public non-virtual in the leaf classes
Any user attempt to compare two objects of different types will not compile because the base function is protected, and the leaf classes can leverage the parent's version to compare that part of the data.
For this sort of hierarchy I would definitely follow the Scott Meyer's Effective C++ advice and avoid having any concrete base classes. You appear to be doing this in any case.
I would implement operator== as a free functions, probably friends, only for the concrete leaf-node class types.
If the base class has to have data members, then I would provide a (probably protected) non-virtual helper function in the base class (isEqual, say) which the derived classes' operator== could use.
E.g.
bool operator==(const B& lhs, const B& rhs)
{
return lhs.isEqual( rhs ) && lhs.bar == rhs.bar;
}
By avoiding having an operator== that works on abstract base classes and keeping compare functions protected, you don't ever get accidentally fallbacks in client code where only the base part of two differently typed objects are compared.
I'm not sure whether I'd implement a virtual compare function with a dynamic_cast, I would be reluctant to do this but if there was a proven need for it I would probably go with a pure virtual function in the base class (not operator==) which was then overriden in the concrete derived classes as something like this, using the operator== for the derived class.
bool B::pubIsEqual( const A& rhs ) const
{
const B* b = dynamic_cast< const B* >( &rhs );
return b != NULL && *this == *b;
}
If you dont want to use casting and also make sure you will not by accident compare instance of B with instance of C then you need to restructure your class hierarchy in a way as Scott Meyers suggests in item 33 of More Effective C++. Actually this item deals with assignment operator, which really makes no sense if used for non related types. In case of compare operation it kind of makes sense to return false when comparing instance of B with C.
Below is sample code which uses RTTI, and does not divide class hierarchy into concreate leafs and abstract base.
The good thing about this sample code is that you will not get std::bad_cast when comparing non related instances (like B with C). Still, the compiler will allow you to do it which might be desired, you could implement in the same manner operator< and use it for sorting a vector of various A, B and C instances.
live
#include <iostream>
#include <string>
#include <typeinfo>
#include <vector>
#include <cassert>
class A {
int val1;
public:
A(int v) : val1(v) {}
protected:
friend bool operator==(const A&, const A&);
virtual bool isEqual(const A& obj) const { return obj.val1 == val1; }
};
bool operator==(const A& lhs, const A& rhs) {
return typeid(lhs) == typeid(rhs) // Allow compare only instances of the same dynamic type
&& lhs.isEqual(rhs); // If types are the same then do the comparision.
}
class B : public A {
int val2;
public:
B(int v) : A(v), val2(v) {}
B(int v, int v2) : A(v2), val2(v) {}
protected:
virtual bool isEqual(const A& obj) const override {
auto v = dynamic_cast<const B&>(obj); // will never throw as isEqual is called only when
// (typeid(lhs) == typeid(rhs)) is true.
return A::isEqual(v) && v.val2 == val2;
}
};
class C : public A {
int val3;
public:
C(int v) : A(v), val3(v) {}
protected:
virtual bool isEqual(const A& obj) const override {
auto v = dynamic_cast<const C&>(obj);
return A::isEqual(v) && v.val3 == val3;
}
};
int main()
{
// Some examples for equality testing
A* p1 = new B(10);
A* p2 = new B(10);
assert(*p1 == *p2);
A* p3 = new B(10, 11);
assert(!(*p1 == *p3));
A* p4 = new B(11);
assert(!(*p1 == *p4));
A* p5 = new C(11);
assert(!(*p4 == *p5));
}
I was having the same problem the other day and I came up with the following solution:
struct A
{
int foo;
A(int prop) : foo(prop) {}
virtual ~A() {}
virtual bool operator==(const A& other) const
{
if (typeid(*this) != typeid(other))
return false;
return foo == other.foo;
}
};
struct B : A
{
int bar;
B(int prop) : A(1), bar(prop) {}
bool operator==(const A& other) const
{
if (!A::operator==(other))
return false;
return bar == static_cast<const B&>(other).bar;
}
};
struct C : A
{
int baz;
C(int prop) : A(1), baz(prop) {}
bool operator==(const A& other) const
{
if (!A::operator==(other))
return false;
return baz == static_cast<const C&>(other).baz;
}
};
The thing I don't like about this is the typeid check. What do you think about it?
If you make the reasonable assumption that the types of both objects must be identical for them to be equal, there's a way to reduce the amount of boiler-plate required in each derived class. This follows Herb Sutter's recommendation to keep virtual methods protected and hidden behind a public interface. The curiously recurring template pattern (CRTP) is used to implement the boilerplate code in the equals method so the derived classes don't need to.
class A
{
public:
bool operator==(const A& a) const
{
return equals(a);
}
protected:
virtual bool equals(const A& a) const = 0;
};
template<class T>
class A_ : public A
{
protected:
virtual bool equals(const A& a) const
{
const T* other = dynamic_cast<const T*>(&a);
return other != nullptr && static_cast<const T&>(*this) == *other;
}
private:
bool operator==(const A_& a) const // force derived classes to implement their own operator==
{
return false;
}
};
class B : public A_<B>
{
public:
B(int i) : id(i) {}
bool operator==(const B& other) const
{
return id == other.id;
}
private:
int id;
};
class C : public A_<C>
{
public:
C(int i) : identity(i) {}
bool operator==(const C& other) const
{
return identity == other.identity;
}
private:
int identity;
};
See a demo at http://ideone.com/SymduV
I think this looks weird:
void foo(const MyClass& lhs, const MyClass& rhs) {
if (lhs == rhs) {
MyClass tmp = rhs;
// is tmp == rhs true?
}
}
If implementing operator== seems like a legit question, consider type erasure (consider type erasure anyways, it's a lovely technique). Here is Sean Parent describing it.
Then you still have to do some multiple-dispatching. It's an unpleasant problem. Here is a talk about it.
Consider using variants instead of hierarchy. They can do this type of things easyly.