Что означает «оператор = должен быть нестатическим членом»? - PullRequest
22 голосов
/ 16 мая 2009

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

template<class T>
void operator=(const list<T>& lst)
{
    clear();
    copy(lst);
    return;
}

но я получаю эту ошибку при попытке скомпилировать:

container_def.h(74) : error C2801: 'operator =' must be a non-static member

Кроме того, если это помогает, строка 74 является последней строкой определения с "}".

Ответы [ 4 ]

20 голосов
/ 16 мая 2009

В точности то, что говорится: перегрузки оператора с 1 параметром должны быть функциями-членами. (объявлено внутри класса)

template<class T>
void list<T>::operator=(const list<T>& rhs)
{
    ...
}

Кроме того, вероятно, будет хорошей идеей вернуть LHS из =, чтобы вы могли связать его (например, a = b = c) - так что сделайте это list<T>& list<T>::operator=....

18 голосов
/ 16 мая 2009

Поместите этот оператор в определение вашего класса. Он должен быть участником, потому что operator= является особенным, и вы не получите что-либо, если в любом случае будете писать его как нечлен. У оператора, не являющегося членом, есть два важных основных преимущества:

  • Неявные преобразования правой и левой части вызова оператора
  • Не нужно знать о внутренностях класса. Функция может быть реализована как не-член, не являющийся другом.

Для operator= оба не могут быть использованы. Присвоение временного результата преобразования не имеет смысла, и operator= в большинстве случаев потребуется доступ к внутренним компонентам. Кроме того, C ++ автоматически предоставляет специальный operator=, если вы его не предоставляете (так называемый оператор копирования-назначения). Возможность перегрузить operator= как не-член привела бы к дополнительной сложности, по-видимому, без практической выгоды, и поэтому это недопустимо.

Поэтому измените свой код так, чтобы он выглядел следующим образом (предполагается, что operator= является , а не оператором копирования-назначения, но присваивает list<T> что-то еще. Это не ясно из вашего вопроса):

class MyClass {
...
    template<class T>
    MyClass& operator=(const list<T>& lst)
    {
        clear();
        copy(lst);
        return *this;
    }
...
};

Довольно стандартно, что operator= снова возвращает ссылку на себя. Я рекомендую вам придерживаться этой практики. Он будет выглядеть знакомым для программистов и может вызвать сюрпризы, если он неожиданно вернет void.

6 голосов
/ 16 мая 2009

Если вы перегружаете оператор как функцию-член, вам следует использовать этот шаблон:

class A {
  A& operator=(const A& other) {
    if (this != &other) {
      ...
    }
    return *this;
  }
}

Три вещи на заметку:

  1. Проверка на самостоятельное назначение с оператором назначения (как указано выше);
  2. Аргумент должен быть константной ссылкой; и
  3. Возвращает результат операции как неконстантную ссылку, где вы возвращаете * this, чтобы разрешить цепочку операторов.

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

class A {
  friend const A& operator+(const A& a, const A& b);
  ...
}
const A& operator+(const A& a, const A& b) {
  A& ret = ...
  return ret;
}

Этот возвращает константную ссылку, поэтому вы не можете сделать это:

(a + b) = c
0 голосов
/ 16 мая 2009

Из стандарта C ++, «Бинарные операторы»:

"Бинарный оператор должен быть реализован либо нестатической функцией-членом с одним параметром, либо функцией, не являющейся членом-членом, с двумя параметрами"

Он хочет, чтобы вы определили это в классе как член или сделали его статическим методом (в этом случае он должен принимать два параметра (для lval и rval).

...