When the old programming gods were inventing object-oriented programming with classes, they decided when it came to composition and inheritance to have two relationships for an object: "is a" and "has a".
This partially solved the problem of subclasses being different than parent classes but made them usable without breaking code. Because a subclass instance "is a" superclass object and can be substituted directly for it, even though the subclass has more member functions or data members, the "has a" guarantees it will perform all the functions of the parent and have all of its members. So you could say a Point3D "is a" Point , and a Point2D "is a" Point if they both inherit from Point. Additionally a Point3D could be a subclass of Point2D.
Equality between classes is problem domain-specific, however, and the above example is ambiguous as to what the programmer needs for the program to work correctly. Generally, math-domain rules are followed and values of data would generate equality if you limit the scope of the comparision to just in this case two dimensions, but not if you compare all the data members.
So you get a table of narrowing equalities:
Both objects have same values, limited to subset of shared members
Child classes can be equal to parent classes if parent and childs
data members are the same.
Both objects entire data members are the same.
Objects must have all same values and be similar classes.
Objects must have all same values and be the same class type.
Equality is determined by specific logical conditions in the domain.
Only Objects that both point to same instance are equal.
You generally pick the most strict rules that you can that still will perform all the necessary functions in your problem domain. The built-in equality tests for numbers are designed to be as restrictive as they can be for math purposes, but the programmer has many ways around that if that is not the goal, including rounding up/down , truncation, gt,lt,etc.
Objects with timestamps are often compared by their generation time and so each instance must be unique so comparisons get very specific.
The design factor in this case is to determine efficient ways to compare objects. Sometimes a recursive comparison of all objects data members is what you must do, and that can get very expensive if you have lots and lots of objects with lots of data members. Alternatives are to only compare relevant data values, or have the object generate a hash value of its data members concerned for a quick comparison with other similar objects, keep collections sorted and pruned to make comparisons faster and less cpu intensive, and perhaps allow objects that are identical in data to be culled and a duplicate pointer to a single object be put in its place.