Подтвердить что ты не робот

Почему не может использоваться функция, не являющаяся членом, для перегрузки оператора присваивания?

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

class Test
{
    int a;
public:
    Test(int x)
        :a(x)
    {}
    friend Test& operator=(Test &obj1, Test &obj2);
};

Test& operator=(Test &obj1, Test &obj2)//Not implemented fully. just for test.
{
    return obj1;
}

Он вызывает эту ошибку:

ошибка C2801: 'operator =' должен быть нестационарным членом

Почему не может использоваться функция friend для перегрузки оператора присваивания? Компилятор позволяет перегрузить другие операторы, такие как += и -=, используя friend. Какая внутренняя проблема/ограничение в поддержке operator=?

4b9b3361

Ответ 1

Поскольку значение по умолчанию operator=, предоставленное компилятором (по порядку), всегда будет иметь приоритет. То есть ваш друг operator= никогда не будет вызван.

EDIT: этот ответ отвечает на

Какова присущая проблема/ограничение в поддержке = operator?

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

Ответ 2

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

Теперь ответ на этот вопрос дан в книге D & E (Дизайн и эволюция С++). Причиной этого является то, что компилятор всегда объявляет/определяет оператор-экземпляр-экземпляр для класса (если вы не объявляете свой оператор-экземпляр-экземпляр-член).

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

// Class definition
class SomeClass {
  // No copy-assignment operator declared here
  // so the compiler declares its own implicitly
  ...
};

SomeClass a, b;

void foo() {
  a = b;
  // The code here will use the compiler-declared copy-assignment for `SomeClass`
  // because it doesn't know anything about any other copy-assignment operators
}

// Your standalone assignment operator
SomeClass& operator =(SomeClass& lhs, const SomeClass& rhs);

void bar() {
  a = b;
  // The code here will use your standalone copy-assigment for `SomeClass`
  // and not the compiler-declared one 
}

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

Это считалось неприемлемо опасным (и это так), поэтому С++ не позволяет объявлять оператор присваивания копии как автономную функцию.

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

Ответ 3

$13.5.3 - "Оператор присваивания должен быть реализован нестатической функцией-членом только с одним параметром. Поскольку оператор-оператор присваивания экземпляра = неявно объявлен для класса, если он не объявлен пользователем (12.8), оператор присваивания базового класса всегда скрыт оператором присваивания копии производного класса.

Ответ 4

Потому что есть некоторые операторы, которые ДОЛЖНЫ быть членами. Этими операторами являются:
operator[]
 operator=
 operator()
 operator->

и операторов преобразования типов, например operator int.

Хотя можно было бы объяснить, почему именно operator = должен быть членом, их аргумент не может применяться к другим в списке, что заставляет меня поверить, что ответ "Почему" есть "Только потому".

НТН

Ответ 5

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

Ответ 6

Почему функция friend не может использоваться для перегрузки оператора присваивания?

Короткий ответ: Только потому, что.

Несколько длиннее ответ: То, как синтаксис был исправлен. Несколько операторов должны быть функциями-членами. Оператор присваивания является одним из <

Ответ 7

Цель operator= - операция присваивания текущему объекту. Тогда LHS, или lvalue, является объектом того же типа.

Рассмотрим случай, когда LHS является целым или каким-либо другим типом. Это случай, обрабатываемый operator int() или соответствующей функцией operator T(). Следовательно, тип LHS уже определен, но функция non-member operator= может нарушить это.

Следовательно, этого избежать.

Ответ 8

Это сообщение относится к С++ 11

Почему кому-то нужен не-член operator=? Ну, с членом operator=, тогда возможен следующий код:

Test const &ref = ( Test() = something ); 

который создает зависающую ссылку. Оператор, не являющийся членом, зафиксировал бы это:

Test& operator=(Test &obj1, Test obj2)

потому что теперь prvalue Test() не сможет привязываться к obj1. На самом деле эта подпись обеспечит, чтобы мы никогда не возвращали оборванную ссылку (если бы мы не были снабжены одной, конечно) - функция всегда возвращает "действительное" значение lvalue, поскольку оно принудительно вызывает вызов с lvalue.

Однако в С++ 11 теперь есть способ указать, что функция-член может быть вызвана только на lvalues, поэтому вы могли бы достичь той же цели, написав функцию-член:

Test &operator=(Test obj2) &
//                        ^^^

Теперь приведенный выше код с обвисшей ссылкой не сможет скомпилироваться.


NB. operator= должен принимать правую сторону либо по значению, либо по константе. Принимая во внимание ценность, полезно при реализации идиома копирования и свопинга, техника для простой записи безопасных (но не обязательно самых быстрых) операторов копирования и переноса.

Ответ 9

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