struct Data
{
std::string Info; // Object Info
virtual bool operator==(Data& b)
{
return this->Info == b.Info;
}
};
struct Data1: public Data
{
int ID;
virtual bool operator==(Data1& b) override // overrides the bool operator==(Data& b) base function
{
return (this->Info == b.Info) && (this->ID);
}
};
The above code won't compile, I am wandering if it is possible to do so?
I would like my virtual operator function not be class bound.
In other words, maybe something like a template virtual (doesn't exist). I have tried template but of course virtual cannot be paired with template.
struct Data
{
std::string Info; // Object Info
template <class T>
virtual bool operator==(T& b)
{
return this->Info == b.Info; // something along the line
}
};
struct Data1: public Data
{
int ID;
virtual bool operator==(Data1& b) override // overrides the bool operator==(Data& b) base function
{
return (this->Info == b.Info) && (this->ID);
}
};
CodePudding user response:
As a rule, objects of different types can't be equal to each other.
That being the case, for your case, you may be able to get at least reasonably sane results with code on this general order:
struct base {
std::string info;
virtual ~base() = default;
virtual bool cmp(base const& other) const {
return info == other.info;
}
};
struct derived1 : public base {
int i = 0;
bool cmp(base const& other) const override
{
try {
derived1 const& d = dynamic_cast<derived1 const&>(other);
return info == d.info && i == d.i;
}
catch(...) { return false; }
}
};
bool operator==(base const &a, base const &b) {
return a.cmp(b) && b.cmp(a);
}
The logic here may not be obvious. Instead of overloading ==
as a virtual member function, we do the overload as a free function. And the free function does two comparisons, once in each order.
We do that to deal with a case like:
base b;
derived1 d;
if (b == d) std::cout << "oops: shouldn't be equal\n";
If we had overloaded operator==
as a member function, it would tell us that the two objects are equal, which is almost certainly not desired. It does that because the code is equivalent to: if (b.operator==(d))
, which uses the base class comparison operator. Since a reference to the base can refer to an object of derived type, that works, and just compares the base class parts of the two objects, ignoring the fact that one is really a derived object, so the two can't be equal.
With the code the way it's written above, we use both b.operator==(d)
and d.operator==(b)
, so if one of b
or d
is an object of derived type, then we'll only get a true result if the other is also of the (same) derived type. Any attempt at mixing objects of base and derived type will yield false
.
So that does what I think you're asking for. But I'm a long ways from excited about this code even at best. First of all, if comparisons are expensive, it'll get pretty slow, since it does each comparison twice. Second, the code is fragile and difficult to maintain--at the very least, it requires a fairly detailed comment about why it's written the way it is, and why simpler, more obvious code won't work reliably.
Bottom line: yes it works (at least as I perceive what you want), but no I don't like or recommend it.
CodePudding user response:
You need to static_cast
Data1 to Data before comparing it's working in my Compiler
struct Data1 : Data {
int ID;
// cast before compare
bool operator==(Data &b) override {
return static_cast<const Data&>(*this).Info == b.Info && this->ID;
}
};