I have some pointers to a base type of Shape. I want to compare these objects using the == operator. The == operator should obviously return false if the objects are of different derived type. If they are of the same derived type however the members of the derived type should then be compared.
I have read that using the C++ RTTI is bad practice and should only be used in rare and essential circumstances. As far as I can see this problem cannot be generally solved without using the RTTI. Each overloaded == operator would have to check the typeid, and if they are the same perform a dynamic_cast and compare the members. This seems like a common need. Is there some kind of idiom for this problem?
#include <iostream>
using namespace std;
class Shape {
public:
Shape() {}
virtual ~Shape() {}
virtual void draw() = 0;
virtual bool operator == (const Shape &Other) const = 0;
};
class Circle : public Shape {
public:
Circle() {}
virtual ~Circle() {}
virtual void draw() { cout << "Circle"; }
virtual bool operator == (const Shape &Other) const {
// If Shape is a Circle then compare radii
}
private:
int radius;
};
class Rectangle : public Shape {
public:
Rectangle() {}
virtual ~Rectangle() {}
virtual void draw() { cout << "Rectangle"; }
virtual bool operator == (const Shape &Other) const {
// If Shape is a Rectangle then compare width and height
}
private:
int width;
int height;
};
int main() {
Circle circle;
Rectangle rectangle;
Shape *Shape1 = &circle;
Shape *Shape2 = &rectangle;
(*Shape1) == (*Shape2); // Calls Circle ==
(*Shape2) == (*Shape1); // Calls Rectangle ==
}
Use the RTTI.
Use typeid
, but use static_cast
rather than dynamic_cast
.
From a design point of view, I'd say that this is exactly what RTTI is for, any alternative solutions will, by necessity, be uglier.
virtual bool operator == (const Shape &Other) const {
if(typeid(Other) == typeid(*this))
{
const Circle& other = static_cast<const Circle&>(Other);
// ...
}
else
return false;
}
From a performance point of view:
typeid
tends to be cheap, a simple lookup of a pointer stored in the virtual table. You can cheaply compare dynamic types for equality.
Then, once you know you have the right type, you can safely use static_cast
.
dynamic_cast
has a reputation for being slow (that is, slow as in "compared to virtual function calls", not slow as in "compared to a cast in java"), because it will also analyze the class hierarchy to deal with inheritance (and multiple inheritance, too). You don't need to deal with that here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With