Sunday, April 3, 2011

implementing operator== when using inheritance

Hi,

I have a base class which implements the == operator. I want to write another class, inheriting the base class, and which should reimplement the == operator.

Here is some sample code :

#include <iostream>
#include <string>

class Person
{
public:
  Person(std::string Name) { m_Name = Name; };

  bool operator==(const Person& rPerson)
  {
    return m_Name == rPerson.m_Name;
  }

private:
  std::string m_Name;
};

class Employee : public Person
{
public:
  Employee(std::string Name, int Id) : Person(Name) { m_Id = Id; };

  bool operator==(const Employee& rEmployee)
  {

    return (Person::operator==(rEmployee)) && (m_Id == rEmployee.m_Id);
  }

private:
  int m_Id;
};

void main()
{
  Employee* pEmployee1 = new Employee("Foo" , 1);
  Employee* pEmployee2 = new Employee("Foo" , 2);

  if (*pEmployee1 == *pEmployee2)
  {
    std::cout << "same employee\n";
  }
  else
  {
    std::cout << "different employee\n";
  }

  Person* pPerson1 = pEmployee1;
  Person* pPerson2 = pEmployee2;

  if (*pPerson1 == *pPerson2)
  {
    std::cout << "same person\n";
  }
  else
  {
    std::cout << "different person\n";
  }
}

This sample code give the following result :

different employee
same person

Where I would like, even when handling Person* pointers, to make sure they are different.

How am I supposed to solve this problem ?

Thanks !

From stackoverflow
  • You need to make Person::operator== virtual.

    Luc Touraille : -1. Making Person::operator== virtual is not sufficient: Employee::operator== must be rewritten to have the same signature. Moreover, this would still lead to the issue pointed by Douglas, i.e. assymetry of the comparison operation, which is...weird.
    JohnMcG : I don't think you can make operators virtual.
  • Add a virtual function int Compare(const Person& rPerson) and use that in your operators

  • There is no neat solution to this problem.

    Which is not a problem actually, in C++. What sense does it makes to compare entities on a equality basis?

    EDIT: a few links to meditate regarding the pertinence of equality applied to entities:

    Smasher : I don't get your point. Can you explain in more detail, why such a comparison doesn't make sense?
    Luc Hermitte : My point is that equality make no sense on entities, and that the OP is wasting his times solving something that is not to be solved, nor can be solved (see Java debates on isEquals implementation)
    Luc Hermitte : ...Take twins, they are very similar, in some sense we may see them as equals. But who cares ? People are either identical, or not...
    Luc Touraille : I totally agree, but maybe you should develop your answer a little, to explain what are entity and value semantics, and evoke the similarity with Java equals.
    Johannes Schaub - litb : never thought of this deeply. looks like i have to read about something the next hours. lol :)
    Luc Hermitte : Unfortunately, I can't found THE link that explains everything in simple words. I know it, I feel it, but I can't make a short answer on the subject.
    Johannes Schaub - litb : yeah thanks Luc, very inspiring
  • You still have a major problem if you have one person and one employee - the person may compare equal to the employee, but not the employee to the person. i.e:

    (employee == person) != (person == employee)
    

    This is a bad thing (tm). Basically you've made an equality operator that isn't symmetric

    Edit:

    Ok, no virtual operators - add the virtual Compare function suggested elsewhere I think - but you still have the symmetric problem.

  • You can also take operator== outside of the class scope. In which case, you can either create necessary overloads or make it generic by way of templates.

  • eduffy, Douglas Leeder - not possible - sorry. You need to read the language specification.

    In parameter type changes in the hierarchy.

  • The big question here is - how do you determine equality?

    Can any object be compared to any other object in the hierarchy? Can only objects of the same type be compared? Where does the criteria for the comparison live?

    The solution implementation will depend on the answers to these questions.

  • It doesn't make sense to have the same person equal two different employees but that is what you class design allows. You are better off arranging for identity to be attached to a person. You then ask if a.identity() == b.identity().

  • In order to make operator== symmetric you have to have a person and employee with the same shared details differ so that:

    Person p("Foo");
    Employee e("Foo" , 1);
    p == e; // false
    e == p; // false
    

    This is unintuitive but necessary.

    To do this you can use the typeid keyword

    bool operator==(const Person& other) const
    {
         return m_Name == other.m_Name && typeid(other) == typeid(*this);
    }
    

    Of course Person must be a polymorphic type (have at least one virtual function).

  • What you want to do is essentiall "virtualize" the comparison operator.

    Since operators cannot be virtual, you will need to delegate it to something else. Here's one possible solution.

    class Person
    {
       public:
          /* ... */
          bool operator==(const Person& rhs)
          {
             return m_Name == rPerson.m_Name && this->doCompare(rhs);
          }
       private:
          virtual bool doCompare() = 0;
       };
    }
    class Employee : public Person
    {
       /* ... */
       private:
          virtual bool doCompare(const Person& rhs)
          {
             bool bRetval = false;
             const Employee* pRHSEmployee = dynamic_cast<const Employee*>(&rhs);
             if (pEmployee)
             {
                bRetval = m_Id == pRHSEmployee->m_Id
             }
             return bRetval;
          }
    };
    

    The question didn't make clear whether Person needs to be a concrete class. If so, you can make it not pure-virtual, and implement it to return true.

    This also uses RTTI, which you may or may not be happy with.

    Johannes Schaub - litb : c++ allows operators to be virtual. but i wouldn't make them virtual. polymorphism and operators actually don't fit together very well (and free operator functions obviously can't be virtual at all).
    Pete Kirkham : If you are going to do this, then you should call both `this->doCompare(that)` and `that.doCompare(*this)` to ensure symmetry

0 comments:

Post a Comment