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!
Related
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;
}
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
Here is the thing. I have one base class and 4 child classes.
class Base{
public:
virtual int getType() const = 0;
};
class Type1 : public Base{
public:
virtual int getType() const {
return 1;
};
};
class Type2 : public Base{
public:
virtual int getType() const {
return 2;
};
};
class Type3 : public Base{
public:
virtual int getType() const {
return 3;
};
};
class Type4 : public Base{
public:
virtual int getType() const {
return 4;
};
};
I need to overload the == and != operators which do the same thing for all child classes, just retrieve the type values and compare them. So I would naturally implement the operator in the Base class with references to Base as both operands but when I do that, my IDE starts screaming when I use the operators on child views, that it cannot compare structs.
So the question is. Is there a way I can implement the operators just once without having to specify them for each combination of child classes ?
Thanks!
I do not have any problem with this operator:
bool operator==(Base const& x, Base const& y)
{
return x.getType() == y.getType();
}
unless with an accessibility issue: Your getType function is private. If you do not provide any access modifier with classes, all members, variables and functions, are implicitly private.
So you either need a friend declaration or make the getType function public.
class Base {
public:
virtual int getType() const = 0;
bool operator ==(const Base &b) const {
return getType() == b.getType();
}
};
class Type1 : public Base {
public:
virtual int getType() const {
cout << "Type1.getType()" << endl;
return 1;
};
};
class Type2 : public Base {
public:
virtual int getType() const {
cout << "Type2.getType()" << endl;
return 2;
};
};
Usage:
Base *t1 = new Type1(), *t2 = new Type2();
bool res1 = *t1 == *t1; // true, calls Type1.getType() twice
bool res2 = *t1 == *t2; // false, calls Type1.getType() and Type2.getType()
Yes, you can do it in your Base class. There will be no error for doing this.
class Base{
public:
virtual int getType() const = 0;
bool operator==(const Base& rhs) const{
return getType() == rhs.getType();
}
bool operator!=(const Base& rhs) const{
return !(*this == rhs);
}
};
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 */
}
};