Comparing Polymorphic Base Types in C++ without RTTI

c++, polymorphism

Solution

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.

Problem

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 == } ```

Original source