2009-02-19 8 views
9

Mam klasę podstawową, która implementuje operator ==. Chcę napisać inną klasę, dziedzicząc klasę podstawową, i która powinna ponownie wdrożyć operatora ==.implementujący operator == przy dziedziczeniu

Oto przykładowy kod:

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

Ten przykładowy kod daje następujący wynik:

different employee 
same person 

Gdzie chciałbym, nawet podczas pracy osoby * wskazówek, aby upewnić się, że są różne .

Jak mam rozwiązać ten problem?

Dzięki!

+0

Wierzę, że próbujesz rozwiązać niewłaściwy problem. jeśli potrzebujesz operatora ==, który działa w oparciu o typ referencyjny/wskaźnikowy, nie powinieneś był używać dziedziczenia w pierwszej kolejności. – hawk

Odpowiedz

8

To, co chcesz zrobić, to zasadniczo "zwirtualizować" operatora porównania.

Ponieważ operatorzy nie mogą być wirtualni, musisz przekazać to zadanie innej osobie. Oto jedno możliwe rozwiązanie.

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

Pytanie nie wyjaśnia, czy osoba musi być konkretną klasą. Jeśli tak, możesz sprawić, by nie była czysto wirtualna i zaimplementować ją, aby zwracała wartość true.

To również używa RTTI, z którego możesz być zadowolony.

+0

C++ pozwala operatorom być wirtualnymi. ale nie uczyniłbym ich wirtualnymi. polimorfizm i operatory faktycznie nie pasują do siebie bardzo dobrze (a wolne funkcje operatora oczywiście w ogóle nie mogą być wirtualne). –

+4

Jeśli zamierzasz to zrobić, powinieneś wywołać zarówno 'this-> doCompare (that)' oraz 'that.doCompare (* this)', aby zapewnić symetrię –

0

Musisz wykonać Person :: operator == virtual.

+0

-1. Tworzenie Person :: operator == virtual nie jest wystarczające: Employee :: operator == musi zostać przepisany, aby mieć ten sam podpis. Co więcej, nadal prowadziłoby to do kwestii wskazanej przez Douglasa, tj. Asymetrii operacji porównania, która jest ... dziwna. –

+0

Nie sądzę, że możesz sprawić, że operatorzy będą wirtualni. – JohnMcG

7

Dodaj wirtualny funkcja int Porównaj (const Osoba & rPerson) i używać w swoich operatorów

5

Nie ma schludny rozwiązanie tego problemu.

Co nie jest właściwie problemem, w C++. Jaki sens ma porównywanie podmiotów na zasadzie równości?

EDIT: kilka linków do medytacji dotyczące trafności równości stosowane do podmiotów:

+0

Nie rozumiem. Czy możesz wyjaśnić bardziej szczegółowo, dlaczego takie porównanie nie ma sensu? – jpfollenius

+0

Chodzi mi o to, że równość nie ma sensu dla podmiotów, i że OP marnuje czas na rozwiązanie czegoś, czego nie da się rozwiązać, ani nie może być rozwiązany (patrz dyskusje Java na temat implementacji isEquals) –

+0

... Weź bliźnięta, są one bardzo podobne, w pewnym sensie możemy je postrzegać jako równe. Ale kogo to obchodzi ? Ludzie są albo identyczni, albo nie ... –

5

Wciąż masz poważny problem, jeśli masz jedną osobę i jednego pracownika - osoba może porównać równa pracownika, ale nie pracownika do osoby. tj .:

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

To jest zła rzecz (tm). Zasadniczo po dokonaniu operator równości, które nie jest symmetric

Edit:

Ok, nie operatorzy wirtualni - dodać wirtualny Porównaj funkcję zaproponował gdzie indziej myślę - ale wciąż masz problem symetrycznego.

0

Możesz również zabrać operatora == poza zasięg klasy. W takim przypadku możesz albo utworzyć konieczne przeciążenia, albo uczynić go ogólnym za pomocą szablonów.

2

Najważniejsze pytanie brzmi: jak określić równość?

Czy można porównać dowolny obiekt z dowolnym obiektem w hierarchii? Czy można porównywać tylko obiekty tego samego typu? Gdzie znajdują się kryteria porównania?

Realizacja rozwiązania zależy od odpowiedzi na te pytania.

1

Nie ma sensu, aby ta sama osoba była równa dwóm różnym pracownikom, ale na to pozwala projektowanie klas.Lepiej zorganizujcie tożsamość, która będzie przywiązana do osoby. Następnie pytasz, czy a.identity() == b.identity().

1

Aby operator== symetryczne trzeba mieć osoby i pracownika z tymi samymi danymi udostępnionymi różnią się więc, że:

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

To jest nieintuicyjne, ale konieczne.

Aby to zrobić, można użyć typeid keyword

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

Oczywiście Person musi być typ polimorficzny (mają co najmniej jedną funkcję wirtualną).

Powiązane problemy