Virtual Equal Function on C++ - c++

I am trying to do something like:
class A
{
public:
A() = default;
~A() = default;
public:
bool operator==(const A& a)
{
return this->equal(a);
};
private:
virtual bool equal(const A& other) const = 0;
};
class B : public A
{
public:
B() = default;
~B() = default;
private:
virtual bool equal(const A& other) const override
{
const B* b = dynamic_cast<const B*>(&other);
if (!b)
return false;
return m_example == b->m_example;
}
private:
double m_example; //This is just an example data I don't need specific solution for double :)
};
Goal: Only equality possible is between classes of same type = B.
Is that ok?
Is there a standard solution to have a virtual equal operator?
I will be inherting from A a lot (4/8 classes), how can I do this in a clean way, the check if the pointer is null looks very ugly.
Could you please help me?

It's a matter of opinion whether dynamic casts are ugly, or not. It's an endless debate, but it doesn't matter here. That's because dynamic casts are not needed here. This can be done, cleanly, using inheritance:
class B; // Forward declaration.
class A {
// Same as above
private:
virtual bool equal(const A& other) const = 0;
virtual bool equal(const B& other) const { return false; }
};
// ... B class:
bool equal(const A& other) const override
{
return other.equal(*this);
}
bool equal(const B &other) const override
{
return m_example == other.m_example;
}

Related

Virtual Equal Function between templated classes (C++)

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!

Polymorphism and get object type in C++ [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
Let's say that I have 4 classes, B,C,D,E that inherit from A(abstract base class).
Also I have a container (std::vector) of type A* whose contents point to either of
B,C,D,E objects.
Here are some rules:
If a B object and a C object interact, they get removed from the vector and in their place a D object gets created.
Also, C + D = E
Now, suppose that I randomly choose one of said vector contents; how would I go about knowing which object is of which type, in order to implement an interaction mechanic?
NOTE: I do not wish to use the typeid operator, a dynamic cast or flags. Any other solutions?
Here is some code
#include <iostream>
class A {
protected:
int v;
public:
A(){}
~A(){}
};
class B :public A {
public:
B(){}
~B(){}
};
class C : public A {
public:
C(){}
~C(){}
};
class D : public A {
public:
D(){}
~D(){}
};
class E : public A {
public:
E(){}
~E(){}
};
int main()
{
std::vector<A*> container;
return 0;
}
How would I implement the interact function(s) ?
Your problem sounds like a bad abstraction. So actually you're not solving the right problem. You should use inheritance when you don't need to know the exact type of the object, but instead rely on runtime polymorphism.
You can bake in some flags, like virtual function that will return an id of each type, but is rather workaround, not a solution. It is also easy to get it wrong.
class A
{
...
virtual int get_id() = 0;
}
Variants
Instead of polymorphism, if the types are fixed (e.g. you don't plan to add or remove classes), you can use std::variant<> (C++17) or boost.variant. To interact with it, you will need to use visitors and call std::visit(). May be it will be harder to interact with it, but, in my opinion, it will better fit as a solution for the problem you described.
You may use virtual functions to do the multiple dispatch
struct B;
struct C;
struct D;
struct E;
struct A
{
virtual ~A() = default;
virtual std::unique_ptr<A> interactWithA(const A&) const = 0;
//protected:
virtual std::unique_ptr<A> interactWithB(const B&) const = 0;
virtual std::unique_ptr<A> interactWithC(const C&) const = 0;
virtual std::unique_ptr<A> interactWithD(const D&) const = 0;
virtual std::unique_ptr<A> interactWithE(const E&) const = 0;
};
// Your interact rules
template <typename LHS, typename RHS>
std::unique_ptr<A> interact(const LHS&, const RHS&) { return nullptr; }
// Note that definitions and declarations must be split in reality
// to be able to compile it
std::unique_ptr<A> interact(const B&, const C&) { return std::make_unique<D>(); }
std::unique_ptr<A> interact(const C&, const D&) { return std::make_unique<E>(); }
// Maybe the reflexive case, C/B D/C ?
// The derived classes
struct B : A
{
std::unique_ptr<A> interactWithA(const A& a) const override { return a.interactWithB(*this); }
// Even if code look similar for other inherited class
// the difference is in the runtime type of the objects are known.
std::unique_ptr<A> interactWithB(const B& rhs) const override { return interact(rhs, *this); }
std::unique_ptr<A> interactWithC(const C& rhs) const override { return interact(rhs, *this); }
std::unique_ptr<A> interactWithD(const D& rhs) const override { return interact(rhs, *this); }
std::unique_ptr<A> interactWithE(const E& rhs) const override { return interact(rhs, *this); }
};
struct C : A
{
std::unique_ptr<A> interactWithA(const A& a) const override { return a.interactWithC(*this); }
std::unique_ptr<A> interactWithB(const B& rhs) const override { return interact(rhs, *this); }
std::unique_ptr<A> interactWithC(const C& rhs) const override { return interact(rhs, *this); }
std::unique_ptr<A> interactWithD(const D& rhs) const override { return interact(rhs, *this); }
std::unique_ptr<A> interactWithE(const E& rhs) const override { return interact(rhs, *this); }
};
struct D : A
{
std::unique_ptr<A> interactWithA(const A& a) const override { return a.interactWithD(*this); }
std::unique_ptr<A> interactWithB(const B& rhs) const override { return interact(rhs, *this); }
std::unique_ptr<A> interactWithC(const C& rhs) const override { return interact(rhs, *this); }
std::unique_ptr<A> interactWithD(const D& rhs) const override { return interact(rhs, *this); }
std::unique_ptr<A> interactWithE(const E& rhs) const override { return interact(rhs, *this); }
};
struct E : A
{
std::unique_ptr<A> interactWithA(const A& a) const override { return a.interactWithE(*this); }
std::unique_ptr<A> interactWithB(const B& rhs) const override { return interact(rhs, *this); }
std::unique_ptr<A> interactWithC(const C& rhs) const override { return interact(rhs, *this); }
std::unique_ptr<A> interactWithD(const D& rhs) const override { return interact(rhs, *this); }
std::unique_ptr<A> interactWithE(const E& rhs) const override { return interact(rhs, *this); }
};
and then
std::vector<std::unique_ptr<A>> v /* = .. */;
auto a = v[i]->interactWithA(*v[j]);
if (a) {
// Remove v[i] and v[j]
// Insert a
}

How to implement operator== for polymorphic classes in c++ [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What’s the right way to overload operator== for a class hierarchy?
I have a base class and several derived classes like in the following code:
class Base
{
public:
friend bool operator==(const Base&, const Base&);
virtual ~Base(){}
private:
virtual bool equals(const Base& other) const = 0;
};
bool operator==(const Base& lhs, const Base& rhs)
{
return lhs.equals(rhs);
}
class A : public Base
{
public:
A(int x) : x_(x){}
private:
virtual bool equals(const Base& other) const;
int x_;
};
bool A::equals(const Base& other) const
{
const A* pA = dynamic_cast<const A*>(&other);
if(!pA) return false;
return x_ == pA->x_;
}
class B : public Base
{
public:
B(double y) : y_(y){}
private:
virtual bool equals(const Base& other) const;
double y_;
};
bool B::equals(const Base& other) const
{
const B* pB = dynamic_cast<const B*>(&other);
if(!pB) return false;
return y_ == pB->y_;
}
To be able to compare two derived classes I want to have operator==. The question is how to achieve this in an object oriented way (e.g. respecting encapsulation, maintainability and extensibility). Are there some recommended patterns to do that? Is there an alternative to the above approach avoiding dynamic_cast?
Your way is not perfect. Consider next class deriving from A:
class AA : public A
{
public:
AA(int x, int y) : A(x), y_(y) {}
private:
virtual bool equals(const Base& other) const;
int y_;
};
bool AA::equals(const Base& other) const
{
const AA* pAA = dynamic_cast<const AA*>(&other);
if(!pAA) return false;
return A::equals(other) && y_ == pAA->y_;
}
then your operatator == breaks fundamental rule, it is not symmetrical relation:
A a(1);
AA aa(1,1);
assert(a == aa);
assert(!(aa == a));
Short fix would be to use typeid:
bool operator==(const Base& lhs, const Base& rhs)
{
return typeid(lhs) == typeid(rhs) && lhs.equals(rhs);
}

Dynamic Casts or Function Overloads?

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.

operator overloading c++

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 */
}
};