www.digitalmars.com [Home] [Search] [D]
Last modified Aug 21, 2002.

Operator Overloading

Overloading is accomplished by interpreting specially named member functions as being implementations of unary and binary operators. No additional syntax is used.

Unary Operator Overloading

Overloadable Unary Operators

op opfunc
- neg
~ com
e++ postinc
e-- postdec

Given a unary overloadable operator op and its corresponding class or struct member function name opfunc, the syntax:

	op a
	
where a is a class or struct object reference, is interpreted as if it was written as:
	a.opfunc()
	

Overloading ++e and --e

Since ++e is defined to be semantically equivalent to (e += 1), the expression ++e is rewritten as (e += 1), and then checking for operator overloading is done. The situation is analogous for --e.

Examples

  1. 	class A { int neg(); }
    	A a;
    	-a;	// equivalent to a.neg();
    	
  2. 	class A { int neg(int i); }
    	A a;
    	-a;	// equivalent to a.neg(), which is an error
    	

Binary Operator Overloading

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:
  1. If a is a struct or class object reference that contains a member named opfunc, the expression is rewritten as:
    	a.opfunc(b)
    	
  2. 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)
    	
  3. 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)
    	
  4. If a or b is a struct or class object reference, it is an error.

Examples

  1. 	class A { int add(int i); }
    	A a;
    	a + 1;	// equivalent to a.add(1)
    	
  2. 	1 + a;	// equivalent to a.add(1)
    	
  3. 	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:

Future Directions

Likely many more operators will become overloadable. But the operators ., &&, ||, ?:, and a few others will likely never be.
Copyright (c) 1999-2002 by Digital Mars, All Rights Reserved