6

Possible Duplicate:
What’s the right way to overload operator== for a class hierarchy?

I have a base class and several derived classes like in the following code:

class Base
{
public:
    friend bool operator==(const Base&, const Base&);
    virtual ~Base(){}

private:
    virtual bool equals(const Base& other) const = 0;
};

bool operator==(const Base& lhs, const Base& rhs)
{
    return lhs.equals(rhs);
}

class A : public Base
{
public:
    A(int x) : x_(x){}

private:
    virtual bool equals(const Base& other) const;
    int x_;
};

bool A::equals(const Base& other) const
{
    const A* pA = dynamic_cast<const A*>(&other);
    if(!pA) return false;
    return x_ == pA->x_;
}

class B : public Base
{
public:
    B(double y) : y_(y){}

private:
    virtual bool equals(const Base& other) const;
    double y_;
};

bool B::equals(const Base& other) const
{
    const B* pB = dynamic_cast<const B*>(&other);
    if(!pB) return false;
    return y_ == pB->y_;
}

To be able to compare two derived classes I want to have operator==. The question is how to achieve this in an object oriented way (e.g. respecting encapsulation, maintainability and extensibility). Are there some recommended patterns to do that? Is there an alternative to the above approach avoiding dynamic_cast?

Community
  • 1
  • 1
MWid
  • 4,429
  • 3
  • 20
  • 20
  • 1
    I presume you want `operator==()` to return `false` when passed one object of type `A` and one of type `B` as these classes are not directly related. But suppose you derive a class `AA` from `A`: What do you want do you want `operator==()` to do when called with one `A` object and one `AA` object? – j_random_hacker Oct 24 '12 at 08:30
  • I think you are looking for multiple dispatch: http://stackoverflow.com/questions/1749534/multiple-dispatch-in-c – jogojapan Oct 24 '12 at 08:31
  • @j_random_hacker Two classes shall compare equal, if they have the same typeid and all member variables have equal values. – MWid Oct 24 '12 at 08:44
  • Then PiotrNycz's answer does what you want, while introducing a minimum of maintenance hassle. – j_random_hacker Oct 24 '12 at 08:47
  • @jogojapan Can you give me any hint how an implementation of `operator==()` using multiple dispatch would look like – MWid Oct 24 '12 at 09:11

1 Answers1

3

Your way is not perfect. Consider next class deriving from A:

class AA : public A
{
public:
    AA(int x, int y) : A(x), y_(y) {}

private:
    virtual bool equals(const Base& other) const;
    int y_;
};

bool AA::equals(const Base& other) const
{
    const AA* pAA = dynamic_cast<const AA*>(&other);
    if(!pAA) return false;
    return A::equals(other) && y_ == pAA->y_;
}

then your operatator == breaks fundamental rule, it is not symmetrical relation:

   A a(1); 
   AA aa(1,1); 
   assert(a == aa);
   assert(!(aa == a));

Short fix would be to use typeid:

bool operator==(const Base& lhs, const Base& rhs)
{
    return typeid(lhs) == typeid(rhs) && lhs.equals(rhs);
}
PiotrNycz
  • 23,099
  • 7
  • 66
  • 112