[ Team LiB ] Previous Section Next Section

Gotcha #86: Friend versus Member Operators

An overloaded operator should allow application of any conversions its argument types support:



class Complex { 


 public:


   Complex( double re = 0.0, double im = 0.0 );


   // . . .


};


For example, the Complex constructor permits a conversion from the predefined numeric types to a Complex. The non-member add function allows this conversion to be performed implicitly on either of its arguments:



Complex add( const Complex &, const Complex & ); 


Complex c1, c2;


double d;





add(c1,c2);


add(c1,d); // add( c1, Complex(d,0.0) )


add(d,c1); // add( Complex(d,0.0), c1 )


The non-member operator + function below permits the same implicit conversions:



Complex operator +( const Complex &, const Complex & ); 


c1 + c2;


operator +(c1,c2); // same as above


c1 + d;


operator +(c1,d); // same as above


d + c1;


operator +(d,c1); // same as above


However, if we implement the binary addition of Complex with a member function, we introduce an asymmetry with respect to implicit conversion:



class Complex { 


 public:


   // member operators


   Complex operator +( const Complex & ) const; // binary


   Complex operator -( const Complex & ) const; // binary


   Complex operator -() const; // unary


   // . . .


};


// . . .


c1 + c2; // fine.


c1.operator +(c2); // fine.


c1 + d; // fine.


c1.operator +(d); // fine.


d + c1; // error!


d.operator +(c1); // error!


The compiler cannot apply an implicit, user-defined conversion to the first argument of a member function. If such a conversion is part of the desired interface, this implies that a member implementation of the binary operator is inappropriate. Non-member friends allow conversions on their first argument. Members allow only is-a conversion. (See also Gotcha #42.)

    [ Team LiB ] Previous Section Next Section