Overloadable Binary Operators
op
|
commutative?
|
opfunc
|
opfunc_r
|
+
|
yes
|
add
|
-
|
-
|
no
|
sub
|
sub_r
|
*
|
yes
|
mul
|
-
|
/
|
no
|
div
|
div_r
|
%
|
no
|
mod
|
mod_r
|
&
|
yes
|
and
|
-
|
|
|
yes
|
or
|
-
|
^
|
yes
|
xor
|
-
|
<<
|
no
|
shl
|
shl_r
|
>>
|
no
|
shr
|
shr_r
|
>>>
|
no
|
ushr
|
ushr_r
|
~
|
no
|
cat
|
cat_r
|
==
|
yes
|
eq
|
-
|
!=
|
yes
|
eq
|
-
|
<
|
yes
|
cmp
|
-
|
<=
|
yes
|
cmp
|
-
|
>
|
yes
|
cmp
|
-
|
>=
|
yes
|
cmp
|
-
|
+=
|
no
|
addass
|
-
|
-=
|
no
|
subass
|
-
|
*=
|
no
|
mulass
|
-
|
/=
|
no
|
divass
|
-
|
%=
|
no
|
modass
|
-
|
&=
|
no
|
andass
|
-
|
|=
|
no
|
orass
|
-
|
^=
|
no
|
xorass
|
-
|
<<=
|
no
|
shlass
|
-
|
>>=
|
no
|
shrass
|
-
|
>>>=
|
no
|
ushrass
|
-
|
~=
|
no
|
catass
|
-
|
Given a binary overloadable operator op and its corresponding class or struct member function name opfunc and opfunc_r, the syntax:
a op b
is interpreted as if it was written as:
a.opfunc(b)
or:
b.opfunc_r(a)
The following sequence of rules is applied, in order, to determine which form is used:
-
If a is a struct or class object reference that contains a member named opfunc, the expression is rewritten as:
-
a.opfunc(b)
-
If b is a struct or class object reference that contains a member named opfunc_r and the operator op is not commutative, the expression is rewritten as:
-
b.opfunc_r(a)
-
If b is a struct or class object reference that contains a member named opfunc and the operator op is commutative, the expression is rewritten as:
-
b.opfunc(a)
-
If a or b is a struct or class object reference, it is an error.
Examples -
class A { int add(int i); }
-
A a;
-
a + 1; // equivalent to a.add(1)
-
-
1 + a; // equivalent to a.add(1)
-
-
class B { int div_r(int i); }
-
B b;
-
1 / b; // equivalent to b.div_r(1)
-
Overloading == and !=
Both operators use the eq() function. The expression (a == b) is rewritten as a.eq(b), and (a != b) is rewritten as !a.eq(b).
The member function eq() is defined as part of Object as:
int eq(Object o);
so that every class object has an eq().
If a struct has no eq() function declared for it, a bit compare of the contents of the two structs is done to determine equality or inequality.
Overloading <, <=, > and >=
These comparison operators all use the cmp() function. The expression (a op b) is rewritten as (a.cmp(b) op 0). The commutative operation is rewritten as (0 op b.cmp(a))
The member function cmp() is defined as part of Object as:
int cmp(Object o);
so that every class object has a cmp().
If a struct has no cmp() function declared for it, attempting to compare two structs is an error.
Note: Comparing a reference to a class object against null should be done as:
if (a === null)
and not as:
if (a == null)
The latter is converted to:
if (a.cmp(null))
which will fail if cmp is a virtual function.
Rationale
The reason for having both eq() and cmp() is that:
-
Testing for equality can sometimes be a much more efficient operation than testing for less or greater than.
-
For some objects, testing for less or greater makes no sense. For these, override cmp() with:
-
class A
-
{
-
int cmp(Object o)
-
{
-
assert(0); // comparison makes no sense
-
return 0;
-
}
-
}
Share with your friends: |