Обычное правило для операторов, которые изменяют левый объект, чтобы быть членами, и бинарных операторов, которые возвращают новый объект, чтобы быть свободными функциями;главная мотивация последнего заключается в том, что компилятор не будет преобразовывать левую часть в соответствие с элементом;если ваш класс поддерживает любые неявные преобразования, то все обычные бинарные операторы должны быть свободными функциями, так что те же правила преобразования применяются
для левой и правой сторон, например:
class Complex
{
public:
Complex(double r, double i = 0.0);
bool operator==( Complex const& other ) const;
};
Complex a;
// ...
if ( a == 1.0 ) // OK
// ...
if ( 1.0 == a ) // error.
но:
class Complex
{
public:
Complex(double r, double i = 0.0);
friend bool operator==( Complex const& lhs, Complex const& rhs ) const;
};
Complex a;
// ...
if ( a == 1.0 ) // OK
// ...
if ( 1.0 == a ) // OK
Один из элегантных способов добиться этого - определить основные операции в терминах функций-членов - для таких вещей, как +
или -
, этибудет operator+=
и operator-=
;для сравнения вам нужно определить произвольные соглашения, член isEqual
или compare
(который будет возвращать <
, ==
или >
ноль в соответствии с результатами, а затем наследоваться от шаблона построки:
template <typename T>
class ArithmeticOperators
{
friend T operator+( T const& lhs, T const& rhs )
{
T result( lhs );
result += rhs;
return result;
}
// And so on, for all of the binary operators.
};
class Complex : public ArithmeticOperators<Complex>
{
public:
// ...
Complex& operator+=( Complex const& other );
// etc.
};
Обратите внимание, что есть некоторый аргумент для того, чтобы сделать функции operator <op>=
также свободными функциями: тот факт, что свободная функция будет принимать неконстантную ссылку в качестве первого аргумента, итаким образом, требуется lvalue (например, встроенный operator <op>=
). Однако это не обычная практика, вероятно, потому что operator=
должен быть членом, и кажется более естественным обрабатывать operator <op>=
втот же мантер.