HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Equals method implemented in the class

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
themethodimplementedequalsclass

Problem

Is this a proper way to implement an equality check? In Equals method, I am relying on bad_cast exception to know if the objects are of the same class or not.

Is there any other way to implement Equals() in C++?

class Shape
{
public:
    virtual ~Shape() = 0;
    bool operator==(const Shape& s) 
    {
        return Equals(s);
    }

    virtual bool Equals(const Shape& s) = 0;        
};

class Circle : public Shape
{

    bool Equals(const Shape& c) override
    {
        try
        {
            const Circle& other = dynamic_cast(c);
                      // condition to check equality.
        }
        catch(std::bad_cast&)
        {
            return false;
        }
        catch(...)
        {
            throw;
        }
    }
};

class Square : public Shape   
{
    bool Equals(const Shape& s)  override
    {       
        try
        {
            const Square& other = dynamic_cast(s);
                      // condition to check equality.
        }
        catch(std::bad_cast&)
        {
            return false;
        }
        catch(...)
        {
            throw;
        }       
    }
};

typedef std::shared_ptr ShapePtr;
typedef std::vector Shapes;

Shapes LoadShapes()
{
    Shapes shapes;
    shapes.push_back(std::make_shared(42));
    shapes.push_back(std::make_shared(52));
    shapes.push_back(std::make_shared(62));
    shapes.push_back(std::make_shared(10));
    return shapes;
}

int main()
{
    auto circle = std::make_shared(42);
    auto shapes = LoadShapes();
    for ( auto& shape : shapes)
    {
        if ( *shape == *circle)
        {
            std::cout << *shape << "\n";
        }
    }
}


EDIT

Made the operator== as non-virtual method.

Solution

Sorry to bump this one year old question, but there is something inherently wrong in your equality check if you ever extend to more than one level of inheritance.

Consider a class Foo deriving from Circle, assuming the same implementation (with changed types of course).

Foo foo;
Circle circle;
Shape & shapeFoo = foo;
Shape & shapeCircle = circle;

// these two should behave the same, but they don't:
std::cout << (shapeFoo == shapeCircle) << std::endl;
std::cout << (shapeCircle == shapeFoo) << std::endl;


Why does this fail?

shapeFoo == shapeCircle will call shapeFoo.Equals(shapeCircle) which will be dispatched on the implementation of Equals in class Foo. There the dynamic_cast will fail, correctly returning false.

However shapeCircle == shapeFoo will call shapeCircle.Equals(shapeFoo) which will be dispatched on the implementation of Equals in class Circle. There the dynamic_cast will succeed (as Foo is a descendant of Circle). Then the method will compare only the attributes of Circle, probably returning true.

Code Snippets

Foo foo;
Circle circle;
Shape & shapeFoo = foo;
Shape & shapeCircle = circle;

// these two should behave the same, but they don't:
std::cout << (shapeFoo == shapeCircle) << std::endl;
std::cout << (shapeCircle == shapeFoo) << std::endl;

Context

StackExchange Code Review Q#10531, answer score: 6

Revisions (0)

No revisions yet.