代码之家  ›  专栏  ›  技术社区  ›  Jérôme

使用继承时实现运算符==

c++
  •  9
  • Jérôme  · 技术社区  · 15 年前

    我有一个实现==运算符的基类。 我想写另一个类,继承基类,它应该重新实现==运算符。

    以下是一些示例代码:

    #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";
      }
    }
    

    此示例代码给出以下结果:

    different employee
    same person
    

    在我想要的地方,即使在处理人*指针时,也要确保它们是不同的。

    我该如何解决这个问题?

    谢谢!

    9 回复  |  直到 6 年前
        1
  •  8
  •   JohnMcG    14 年前

    您需要做的是将比较运算符“虚拟化”。

    由于运算符不能是虚拟的,因此需要将其委托给其他对象。这里有一个可能的解决方案。

    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;
          }
    };
    

    这个问题没有弄清楚人是否需要成为一个具体的班级。如果是这样,您可以使它不是纯虚拟的,并实现它以返回true。

    这也使用RTTI,您可能会或可能不高兴。

        2
  •  7
  •   Juozas Kontvainis    15 年前

    添加虚拟函数int compare(const person&rperson),并在运算符中使用它

        3
  •  6
  •   Douglas Leeder    15 年前

    如果你有一个人和一个雇员,你仍然会遇到一个大问题——这个人可以与雇员比较,但不能与雇员比较。即:

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

    这是件坏事。基本上你已经做了一个相等运算符 symmetric

    编辑:

    好吧,没有虚拟运算符-我想在别处添加虚拟比较函数-但是您仍然有对称问题。

        4
  •  6
  •   Luc Hermitte    6 年前

    这个问题没有一个很好的解决办法。

    这在C++中实际上不是问题。在平等的基础上比较实体有什么意义?

    编辑:一些关于应用于实体的平等的相关性的思考链接:

    编辑2(2018年11月27日):

    这里还有一个问题,它在OO设计中也有它的根源,而不是C++。设计一个具有自反性的比较运算符是不可能的。( x == x )、对称的( x == y <=> y == x )和可传递的( x == y && y == z => x == z ,也符合 Liskov Substitution Principle . 乔舒亚·布洛赫的著作充分证明了这种局限性。 通用程序设计 ,第二版。

    TL;博士:假设我们有 ColouredPoint 继承自 Point ,用于引用的函数 这需要比较一下。如果 _1,2=1,2,蓝色 ,我们将以 _1,2,蓝色=1,2,绿色 . 或者我们拒绝将点与破坏LSP的彩色点进行比较。等等。没有解决办法。我的结论是,继承比较法虽然很吸引人,但不起作用。

        5
  •  2
  •   17 of 26    15 年前

    这里的大问题是-你如何决定平等?

    是否可以将任何对象与层次结构中的任何其他对象进行比较?只能比较同一类型的对象吗?比较的标准在哪里?

    解决方案的实现将取决于这些问题的答案。

        6
  •  1
  •   lilburne    15 年前

    让同一个人平等对待两个不同的员工是没有意义的,但这正是你的课程设计所允许的。你最好把身份安排在一个人身上。然后询问a.identity()==b.identity()。

        7
  •  1
  •   Motti    15 年前

    为了使 operator== 对称您必须让具有相同共享详细信息的人员和员工不同,以便:

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

    这不是必然的,但却是必要的。

    为此,您可以使用 typeid keyword

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

    当然 Person 必须是多态类型(至少有一个虚拟函数)。

        8
  •  0
  •   eduffy    15 年前

    您需要使person::operator==virtual。

        9
  •  0
  •   Sasha    15 年前

    也可以将operator==置于类范围之外。在这种情况下,您可以创建必要的重载,也可以通过模板使其成为泛型。