Search code examples
c++-cliequality

Equality operator, Equals, GetHashCode for const objects in C++ cli


I have created a new managed, reference class in C++ cli. And now I want to overload equality of objects of this class.

public ref class DerivedFromObject {
    virtual bool Equals(Object^ obj) override;
    virtual int GetHashCode() override;
    static bool operator!= (const DerivedFromObject%, const DerivedFromObject%);
    static bool operator== (const DerivedFromObject%, const DerivedFromObject%);
}

As far as I know from C#, operator!= calls operator==, that calls Equals, which refers to GetHashCode.

bool DerivedFromObject::operator==(const DerivedFromObject % a, const DerivedFromObject % b)
{
   a.Equals((Object^)%b); // Error
}

In the snippet above, Equals and GetHashCode cannot be called on a const object, that's why I cannot call Equals from operator==.

How can I mark method that doesn't change the object in C++ cli? Or What the most appropriative way to define equality chain?


Solution

  • There's two things here:

    • .Net doesn't really have the concept of const in the way that C++ does. C++/CLI will enforce the rules that C++ has, but since .Net doesn't use it, no library methods are declared const, so you'll have problems calling just about any method. Rather than being explicitly declared like in C++, it's just by convention that methods like equals don't modify their parameters.
    • Since you used const%, I think you were trying to parallel the C++ convention of passing const& parameters. % is more similar in usage to ** double pointer than to &: You pass things parameters as % (or ^% for reference types) when the method can assign a value to the parameter, and it should be available to the calling method.

    Here's how I would implement this:

    public ref class DerivedFromObject : IEquatable<DerivedFromObject> {
        virtual bool Equals(DerivedFromObject^ other);
        virtual bool Equals(Object^ obj) override;
        virtual int GetHashCode() override;
        static bool operator!= (DerivedFromObject^, DerivedFromObject^);
        static bool operator== (DerivedFromObject^, DerivedFromObject^);
    }
    

    One other thing you said:

    ...Equals, which refers to GetHashCode.

    Be careful here, because it is possible for unequal objects to have the same hash code.

    GetHashCode will need to evaluate everything, and then if the hash codes are equal, then Equals need to evaluate everything again to be sure they're actually equal. It'll probably be more efficient to not look at the hash code, just compare the objects field by field, and bail out as soon as they're not equal.