перегрузка операторов в с ++ - PullRequest
4 голосов
/ 10 августа 2011

Если я хочу перегрузить оператор +, какой прототип правильный?

  1. D operator+(const D& lhs, const D& rhs);
    затем объявить его как функцию друга D.

  2. D operator+(const D& s);
    Затем объявите его как функцию-член D.

Ответы [ 10 ]

3 голосов
/ 10 августа 2011

Первое правильно, второе совершенно неправильно.Вы можете улучшить второе, написав это

D operator+(const D& s) const;

, но это все еще не так.Причина в том, что компилятор будет применять разные правила к левой и правой части вашего оператора + во второй версии.Например, учитывая этот код

class C
{
};

class D
{
public:
  D(const C&);
};

C c;
D d;

d = d + c; // legal with both versions
d = c + d; // not legal with the second version

Разница в том, что компилятор создаст временный объект D из объекта C для аргумента метода или функции, но не сделает этого для вызова метода ввременный объект.

Короче говоря, первая версия одинаково обрабатывает левую и правую стороны и поэтому лучше согласуется с ожиданиями кодировщиков.

2 голосов
/ 10 августа 2011

Я бы посоветовал вам пойти по третьему пути: реализовать operator+= в качестве функции-члена, а затем реализовать operator+ в терминах предыдущего типа:

D operator+=( D lhs, D const & rhs ) {
   lhs += rhs;
   return lhs;
}

Преимущество третьего способазаключается в том, что в основном с одним и тем же кодом вы предоставляете + и +=, и вы получаете возможность реализовать operator+ как свободную функцию, что является преимуществом с точки зрения симметрии, если ваш класс имеет неявные преобразования, онразрешит d + t и t + d для любого объекта d типа D и любого другого объекта t типа, неявно преобразуемого в D.Версия функции-члена будет применять преобразования только к правой стороне, что означает, что d + t будет разрешено, но не t + d.

[предупреждение о саморекламе] Вы можете прочитать более подробное объяснение по этому конкретному вопросу.выпуск здесь

2 голосов
/ 10 августа 2011

Второй должен быть

D operator+(const D& s) const;

Тогда либо хорошо.

Что касается первой необходимости дружить: только если ей действительно нужен доступ к чему-то частному. Обычно вы можете реализовать его в терминах открытого интерфейса, обычно с соответствующим operator+=:

D operator+(D lhs, const D& rhs) {  //copy left-hand side
    return lhs += rhs;  //add the right-hand side and return by value
}
1 голос
/ 10 августа 2011

Я думаю, что оба верны. Но одна вещь, которую вы пропустили (это может или не может применяться), это то, что если левое значение может быть чем-то отличным от D (скажем, целое число или что-то), то вариант 1 работает для этого, например,

D operator+(int lhs, const D& rhs);

Тогда вы можете сделать что-то вроде:

D d1;

D d2 = 5 + d1;
1 голос
/ 10 августа 2011

Перейти с первым.Однако, если ему нужен доступ к закрытым членам, только тогда сделайте его friend, в противном случае сделайте его функцией не-друга.

0 голосов
/ 10 августа 2011

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

Что касается случая «производный = базовый + производный», я рекомендую не смешивать операторы семантики значений и полиморфизм, это может иметь непредвиденные последствия из-за различных неявных последовательностей преобразования и объектанарезка.Этот пример может быть эквивалентен derived = Derived(base) + derived, но он также может быть derived = Derived(base + Base(derived)), если у base есть оператор +.

Используйте только явное преобразование и приведение, и вы не столкнетесь с каким-либо таинственным странным поведением.И дважды подумайте, прежде чем реализовывать операторы для полиморфного класса.

0 голосов
/ 10 августа 2011

Принцип наименьшего удивления говорит о том, что ваша перегрузка должна вести себя более или менее похожи на встроенные операторы. Обычное решение здесь не для реализации operator+, а для реализации:

D& operator+=( D const& rhs );

в качестве члена, а затем происходит от чего-то вроде:

template<typename T>
class ArithmeticOperators
{
    friend T operator+( T const& lhs, T const& rhs )
    {
        T result( lhs );
        result += rhs;
        return result;
    }
    //  Same thing for all of the other binary operators...
};

Таким образом, вам не нужно переписывать одно и то же каждый раз, когда вы определяете класс, который перегружает арифметические операторы, и вы гарантированно что семантика + и += соответствует.

(friend в приведенном выше просто для того, чтобы вы могли поставить функцию, вместе с его реализацией, в самом классе, где ADL найдет она.)

0 голосов
/ 10 августа 2011

Первый имеет другое поведение, если D имеет неявные конструкторы.

Рассмотрим

struct D
{
    D(int);
};

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

Тогда вы можете сделать 1 + d и d + 1, что вы не можете сделать с участником operator+ (lhs должно быть D, и преобразование не должно выполняться).

0 голосов
/ 10 августа 2011

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

0 голосов
/ 10 августа 2011

Оба метода почти верны.Это всего лишь два способа сделать почти то же самое.Но когда вам нужно применить бинарный оператор к другим типам, кроме D (например, int + D), вам нужно использовать второй.

Опция 1 даже не должна быть другом, если онане нужен доступ к закрытым членам.

Вариант 2 должен быть немного исправлен.Вы пропали без вести D::.

D D::operator+(const D& s) const {
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...