Почему я должен перегружать оператор C ++ как глобальную функцию (делает STL) и каковы предостережения? - PullRequest
4 голосов
/ 28 сентября 2011

Зачем мне перегружать оператор C ++ () как глобальный, а не как член-функцию.Например, оператор ==.

Почему это делается?например в библиотеках STL.

Ответы [ 3 ]

13 голосов
/ 28 сентября 2011

Обычное правило для операторов, которые изменяют левый объект, чтобы быть членами, и бинарных операторов, которые возвращают новый объект, чтобы быть свободными функциями;главная мотивация последнего заключается в том, что компилятор не будет преобразовывать левую часть в соответствие с элементом;если ваш класс поддерживает любые неявные преобразования, то все обычные бинарные операторы должны быть свободными функциями, так что те же правила преобразования применяются
для левой и правой сторон, например:

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>= втот же мантер.

2 голосов
/ 28 сентября 2011

Если я правильно помню, operator = должна быть функцией-членом. Что касается operator ==, я полагаю, что вы на самом деле имеете в виду не глобальную, а свободную функцию (STL не определяет операторы глобально). Есть несколько вещей, которые следует учитывать, один из которых отделен от самого класса: если ваш оператор может быть определен в терминах открытого интерфейса вашего класса, то вам лучше реализовать его таким образом, чтобы сохранить доступ к внутренним компонентам реализации. до минимума. Другим фундаментальным преимуществом является возможность реализации оператора, в котором ваш тип выступает в качестве второго операнда, учитывая равенство между типами T и U:

bool operator ==( T const& t, U const& u ){ ... }
bool operator ==( U const& t, T const& u ){ ... }

Если объекты типа T и U можно сравнивать одинаково, то имеет смысл, что и t == u, и u == t являются действительными и оба дают одинаковый результат. Если бы вы определяли этот оператор как функцию-член, то один был бы в реализации T, а другой - в реализации U. Теперь рассмотрим U как сторонний тип вне вашего контроля, или даже лучше, это фундаментальный тип, такой как int, теперь у вас нет другого способа предоставить такого оператора, кроме как предоставить его бесплатную версию функции.

0 голосов
/ 28 сентября 2011

Правила сопоставления функции-члена с аргументом отличаются от правил сопоставления первого аргумента свободной функции. Я точно не знаю, чем они отличаются, но, поскольку они различаются, на самом деле предпочтительнее реализовать большинство двоичных операторов в качестве свободных функций вместо функций-членов, чтобы сопоставление аргументов действовало симметрично для обоих аргументов.

Существует исключение для постфикса ++, но это потому, что он на самом деле не является бинарным оператором, а воспроизводит его только при перегрузке, чтобы можно было отличить его от префикса ++.

...