Symmetric && Commutative Operators
💡💡 Have you ever pondered upon the distinctions between 𝗼𝘃𝗲𝗿𝗹𝗼𝗮𝗱𝗶𝗻𝗴 an 𝗼𝗽𝗲𝗿𝗮𝘁𝗼𝗿 in
a C++ class 𝗮𝘀
𝗮 𝗺𝗲𝗺𝗯𝗲𝗿 𝗳𝘂𝗻𝗰𝘁𝗶𝗼𝗻 𝗢𝗥 𝗮𝘀 𝗮𝗻 𝗲𝘅𝘁𝗲𝗿𝗻𝗮𝗹 𝗳𝘂𝗻𝗰𝘁𝗶𝗼𝗻?
In C++, it’s immensely beneficial to be able to overload operators for custom data types defined as
classes. However, we
may have concerns about whether to implement it as a member function or as an external function. Here
are some
𝗰𝗿𝘂𝗰𝗶𝗮𝗹 𝗽𝗼𝗶𝗻𝘁𝘀 to 𝗰𝗼𝗻𝘀𝗶𝗱𝗲𝗿 𝗯𝗲𝗳𝗼𝗿𝗲 𝗺𝗮𝗸𝗶𝗻𝗴 a 𝗱𝗲𝗰𝗶𝘀𝗶𝗼𝗻.
💭💭 Let's consider a scenario where we have a class C with a conversion constructor from int to C type,
and an
overloaded member function operator+ (C). We also have two C objects: C result{}; and C c{}; and an int
variable int x;.
If we try to write "𝗿𝗲𝘀𝘂𝗹𝘁 = 𝗰 + 𝘅;", the first parameter is implicitly received, while the
second parameter is
explicitly passed as a formal parameter of the method. Therefore, the compiler interprets the
instruction as
"𝗿𝗲𝘀𝘂𝗹𝘁 = 𝗰.𝗼𝗽𝗲𝗿𝗮𝘁𝗼𝗿+(𝘅);", implicitly converting the integer x to a data type of C
using the conversion
constructor defined in our class C. However, if we try to do "𝗿𝗲𝘀𝘂𝗹𝘁 = 𝘅 + 𝗰;", the compiler
would throw an
error, as it'd interpret it as "𝗿𝗲𝘀𝘂𝗹𝘁 = 𝘅.𝗼𝗽𝗲𝗿𝗮𝘁𝗼𝗿+(𝗰);", and it’s impossible to
implicitly convert the
parameter x from an integer to type C because in this case, x is not an explicit parameter but an
implicit one. This
brings us to a fundamental rule in C++:
⛔
THE COMPILER DOES NOT PERFORM IMPLICIT CONVERSIONS ON IMPLICIT PARAMETERS.
⛔
🤔🤔 At this point, you might be wondering: "What if we define our operator+() as an external function?"
If operator+()
is defined as an external function, it would receive explicit parameters, allowing for implicit
conversion of all
parameters. However, this approach lacks encapsulation and does not provide access to private
attributes.
⚙️⚙️ Another option to consider when overloading operators in C++ is to implement them as friend
functions. Friend
functions do not receive implicit parameters, which allows for control over implicit conversion. This
approach may not
fully adhere to the principle of encapsulation as it defines the operator as an external function.
Nevertheless, it
provides the advantage of accessing private attributes from the friend operator, which is not possible
when defining
operators as external functions without being friends.
🔥🔥 My Conclusion
-For symmetric or commutative operators where operations may be written in both ways, overload the
operator as an
external function. This allows for implicit conversion of both parameters and may justify deviating from
strict
encapsulation.
-If direct access to private attributes is needed, implement the operator as a friend function.
-Otherwise, implement the operator as a member function to adhere to basic principles of object-oriented
programming in
C++ while retaining access to private attributes.