Перегрузка операторов присваивания

Перегрузка оператора = и сокращенных операторов присваивания (например, +=, -=, *=, /= и др.) осуществляется также как и перегрузка бинарных операторов. Главное отличие заключается в том, что операторы присваивания изменяют сам объект, а не возвращают новый. При использовании «операторных» методов ссылка на объект, расположенный слева от оператора присваивания, передается неявным образом, а объект, расположенный справа от оператора, доступен через параметр. Дружественной функции передаются два параметра. Через первый параметр доступен объект, расположенный от оператора слева, а через второй параметр доступен объект, расположенный от оператора справа. В качестве результата обычно возвращается указатель на исходный объект.

При перегрузке оператора = следует учитывать:

  • если оператор присваивания копированием не перегружен, то автоматически создается оператор присваивания по умолчанию, который выполняет поверхностное копирование объекта. Это важно учитывать, если внутри класса производится динамическое выделение памяти (пример работы с динамической памятью приведен в листинге 13.10). Формат перегрузки оператора присваивания копированием:
<Название класса> &operator=(const <Название класса> &<Объект>);
  • «операторный» метод присваивания перемещением вызывается, когда справа от оператора = находится не константная ссылка r-value, например, временный объект, возвращаемый из функции. Чтобы вызвать «операторный» метод присваивания перемещением явным образом можно воспользоваться функцией move(), которая выполняет приведение значения l-value к r-value. Перегрузка оператора присваивания перемещением также автоматически создается компилятором, однако, если явным образом реализован конструктор копирования или метод присваивания копированием, то метод присваивания перемещением автоматически не создается. Если «операторного» метода присваивания перемещением нет, то вызывается метод присваивания копированием. Формат перегрузки оператора присваивания перемещением:
<Название класса> &operator=(<Название класса> &&<Объект>);
  • при использовании оператора присваивания при инициализации объекта вызывается конструктор копирования или конструктор перемещения, а не перегруженная версия оператора =;
  • перегрузить оператор = с помощью дружественной функции нельзя.

Пример перегрузки операторов присваивания приведен в листинге 14.4.

Листинг 14.4. Перегрузка операторов присваивания

#include <iostream>

class C {
   int x_;
public:
   C() { x_ = 0; }                 // Конструктор по умолчанию
   explicit C(int x) { x_ = x; }   // Обычный конструктор
   C(const C &c) { x_ = c.x_; }    // Конструктор копирования
   C(C &&c) {                      // Конструктор перемещения
      x_ = c.x_; c.x_ = 0;
   }
   int getX() const { return x_; }

   // Присваивание копированием
   C &operator=(const C &obj);     // obj2 = obj1
   // Присваивание перемещением
   C &operator=(C &&obj);          // obj2 = std::move(obj1)
   C &operator=(int x);            // obj  = целое число
   C &operator+=(int x);           // obj += целое число
};

int main() {
   C obj1, obj2;
   obj1 = 10;                              // obj  = целое число
   obj2 = obj1;                            // obj2 = obj1
   obj2 += 20;                             // obj += целое число
   std::cout << obj1.getX() << std::endl;  // 10
   std::cout << obj2.getX() << std::endl;  // 30
   // Множественное присваивание
   obj2 = obj1 = 5;
   std::cout << obj1.getX() << std::endl;  // 5
   std::cout << obj2.getX() << std::endl;  // 5
   // Вызывается конструктор копирования,
   // а не метод C &operator=(const C &obj)!
   C obj3 = obj1;
   std::cout << obj3.getX() << std::endl;  // 5
   // Присваивание перемещением
   obj3 = std::move(obj1);
   std::cout << obj3.getX() << std::endl;  // 5
   std::cout << obj1.getX() << std::endl;  // 0
   // Вызывается конструктор перемещения,
   // а не метод C &operator=(C &&obj)!
   C obj4 = std::move(obj3);
   std::cout << obj4.getX() << std::endl;  // 5
   std::cout << obj3.getX() << std::endl;  // 0
   return 0;
}

C &C::operator=(const C &obj) {           // Присваивание копированием
   if (this == &obj) return *this;        // Случай obj = obj
   x_ = obj.x_;
   return *this;
}
C &C::operator=(C &&obj) {                // Присваивание перемещением
   if (this == &obj) return *this;        // Случай obj = obj
   x_ = obj.x_;
   obj.x_ = 0;
   return *this;
}
C &C::operator=(int x) {                  // obj = целое число
   x_ = x;
   return *this;
}
C &C::operator+=(int x) {                 // obj += целое число
   x_ += x;
   return *this;
}

Учебник C++ (MinGW-W64)
Учебник C++ (MinGW-W64) в формате PDF

Помощь сайту

ЮMoney (Yandex-деньги): 410011140483022

ПАО Сбербанк:
Счет: 40817810855006152256
Реквизиты банка:
Наименование: СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК
Корреспондентский счет: 30101810500000000653
БИК: 044030653
КПП: 784243001
ОКПО: 09171401
ОКОНХ: 96130
Скриншот реквизитов