|
Reflexivity
One of the most convenient reasons to use
global overloaded operators instead of member operators
is that in the global versions, automatic type
conversion may be applied to either operand, whereas with member objects, the
left-hand operand must already be the proper type. If you want both operands to
be converted, the global versions can save a lot of coding. Here’s a small
example:
//: C12:ReflexivityInOverloading.cpp
class Number {
int i;
public:
Number(int ii = 0) : i(ii) {}
const Number
operator+(const Number& n) const {
return Number(i + n.i);
}
friend const Number
operator-(const Number&, const Number&);
};
const Number
operator-(const Number& n1,
const Number& n2) {
return Number(n1.i - n2.i);
}
int main() {
Number a(47), b(11);
a + b; // OK
a + 1; // 2nd arg converted to Number
//! 1 + a; // Wrong! 1st arg not of type Number
a - b; // OK
a - 1; // 2nd arg converted to Number
1 - a; // 1st arg converted to Number
} ///:~
Class Number has both a member
operator+ and a friend operator–. Because
there’s a constructor that takes a single int argument, an
int can be automatically converted to a Number, but only under the
right conditions. In main( ), you can see that adding a
Number to another Number works fine because it’s an exact
match to the overloaded operator. Also, when the compiler sees a Number
followed by a + and an int, it can match to the member function
Number::operator+ and convert the int argument to a Number
using the constructor. But when it sees an int, a +, and a
Number, it doesn’t know what to do because all it has is
Number::operator+, which requires that the left operand already be a
Number object. Thus, the compiler issues an error.
With the friend
operator–, things are different. The compiler needs to fill in both
its arguments however it can; it isn’t restricted to having a
Number as the left-hand argument. Thus, if it sees
1 – a
it can convert the first argument to a
Number using the constructor.
Sometimes you want to be able to restrict
the use of your operators by making them members. For example, when multiplying
a matrix by a vector, the vector must go on the right. But if you want your
operators to be able to convert either argument, make the operator a friend
function.
Fortunately, the compiler will not take
1 – 1 and convert both arguments to Number objects and then
call operator–. That would mean that existing C code might suddenly
start to work differently. The compiler matches the “simplest”
possibility first, which is the built-in operator for the expression 1
–
1.
|
|