The argument for autonomous functions is that these operators must be symmetric according to the types of operands. Implementing relational operators as stand-alone functions rather than methods can have advantages when your class has constructors that allow you to implicitly convert the left operand to your class type. Otherwise, you will have to write explicit constructor calls or overload the operator for other types of left operand (combinatorial explosion).
A friendly declaration is only necessary if you must have access to members of your class. Since relational operators do not need to modify their operands at all, in most cases there are other ways to read members.
Do not use excessive operator overload. Especially when you have many types of classes, such as C1, C2, C3 in your question, it soon becomes unclear, especially for other developers, what your operators say. Consider using a function with a name that clearly describes your intent.
source share