Операторы присваивания
Операторы присваивания изменяют значение объекта.
| Имя оператора | Синтаксис | Перегружаемый | Примеры прототипов (для class T) |
|
|---|---|---|---|---|
| Внутри определения класса | Вне определения класса | |||
| Простое присваивание |
a = b | Да |
T& T::operator =(const T2& b); | Не применимо |
| Присваивание с добавлением |
a += b | Да |
T& T::operator +=(const T2& b); |
T& operator +=(T& a, const T2& b); |
| Присваивание с вычитанием |
a -= b | Да |
T& T::operator -=(const T2& b); |
T& operator -=(T& a, const T2& b); |
| Присваивание с умножением |
a *= b | Да |
T& T::operator *=(const T2& b); |
T& operator *=(T& a, const T2& b); |
| Присваивание с делением |
a /= b | Да |
T& T::operator /=(const T2& b); |
T& operator /=(T& a, const T2& b); |
| Присваивание с остатком |
a %= b | Да |
T& T::operator %=(const T2& b); |
T& operator %=(T& a, const T2& b); |
| Присваивание побитовым И |
a &= b | Да |
T& T::operator &=(const T2& b); |
T& operator &=(T& a, const T2& b); |
| Присваивание побитовым ИЛИ |
a |= b | Да |
T& T::operator |=(const T2& b); |
T& operator |=(T& a, const T2& b); |
| Присваивание побитовым ИСКЛЮЧАЮЩИМ ИЛИ |
a ^= b | Да |
T& T::operator ^=(const T2& b); |
T& operator ^=(T& a, const T2& b); |
| Присваивание со сдвигом влево |
a <<= b | Да |
T& T::operator <<=(const T2& b); |
T& operator <<=(T& a, const T2& b); |
| Присваивание со сдвигом вправо |
a >>= b | Да |
T& T::operator >>=(const T2& b); |
T& operator >>=(T& a, const T2& b); |
Примечания
|
||||
Объяснение
Оператор копирующего присваивания заменяет содержимое объекта a копией содержимого b (b не изменяется). Для типов классов это специальный член-функция, описанный в операторе копирующего присваивания.
| Оператор перемещающего присваивания заменяет содержимое объекта | (с C++11) |
Для типов, не являющихся классами, копирующие и перемещающие присваивания неразличимы и называются прямым присваиванием.
Операторы сложного присваивания заменяют содержимое объекта a результатом бинарной операции между предыдущим значением a и значением b.
Встроенное прямое присваивание
Выражения прямого присваивания имеют вид
lhs = rhs | (1) | |
lhs = {} | (2) | (с C++11) |
lhs = { rhs } | (3) | (с C++11) |
Для встроенного оператора lhs может иметь любой неконстантный скалярный тип, а rhs должен быть неявно преобразуем к типу lhs.
Оператор прямого присваивания ожидает изменяемый lvalue в качестве своего левого операнда и выражение rvalue или список инициализации(с C++11) в качестве своего правого операнда и возвращает lvalue, определяющий левый операнд после модификации. Результат является полем бита, если левый операнд является полем бита.
Для типов, не являющихся классами, правый операнд сначала неявно преобразуется к неприведенному типу левого операнда, а затем его значение копируется в объект, определяемый левым операндом.
Когда левый операнд имеет тип ссылки, оператор присваивания изменяет объект, к которому ссылается.
Если левый и правый операнды идентифицируют перекрывающиеся объекты, поведение является неопределённым (если перекрытие точное и тип тот же).
| Если правый операнд является списком инициализации
| (с C++11) |
| Использование lvalue с квалификатором volatile неклассового типа в качестве левого операнда встроенного оператора прямого присваивания устарело, если выражение присваивания появляется в контексте невычисления или является выражением с отбрасываемым значением. | (с C++20) |
При разрешении перегрузки для пользовательских операторов для каждого типа T, следующие сигнатуры функций участвуют в разрешении перегрузки:
T*& operator=(T*&, T*); | ||
T*volatile & operator=(T*volatile &, T*); |
Для каждого типа перечисления или указателя на член-функцию T, необязательно с квалификатором volatile, следующая сигнатура функции участвует в разрешении перегрузки:
T& operator=(T&, T); |
Для каждой пары A1 и A2, где A1 — арифметический тип (необязательно с квалификатором volatile), а A2 — продвинутый арифметический тип, следующая сигнатура функции участвует в разрешении перегрузки:
A1& operator=(A1&, A2); |
Пример
#include <iostream>
int main()
{
int n = 0; // not an assignment
n = 1; // direct assignment
std::cout << n << ' ';
n = {}; // zero-initialization, then assignment
std::cout << n << ' ';
n = 'a'; // integral promotion, then assignment
std::cout << n << ' ';
n = {'b'}; // explicit cast, then assignment
std::cout << n << ' ';
n = 1.0; // floating-point conversion, then assignment
std::cout << n << ' ';
// n = {1.0}; // compiler error (narrowing conversion)
int& r = n; // not an assignment
r = 2; // assignment through reference
std::cout << n << ' ';
int* p;
p = &n; // direct assignment
p = nullptr; // null-pointer conversion, then assignment
std::cout << p << ' ';
struct { int a; std::string s; } obj;
obj = {1, "abc"}; // assignment from a braced-init-list
std::cout << obj.a << ':' << obj.s << '\n';
}Возможный вывод:
1 0 97 98 1 2 (nil) 1:abc
Встроенное сложное присваивание
Выражения сложного присваивания имеют вид
| lhs op rhs | (1) | |
lhs op {} | (2) | (с C++11) |
lhs op { rhs } | (3) | (с C++11) |
| op | - | один из *=, /= %=, += -=, <<=, >>=, &=, ^=, |= |
| lhs | - | для встроенного оператора lhs может иметь любой арифметический тип, за исключением случаев, когда op является += или -=, которые также принимают указатели с теми же ограничениями, что и + и - |
| rhs | - | для встроенного оператора rhs должен быть неявно преобразуем к lhs |
Поведение каждого встроенного выражения составного присваивания E1 op= E2 (где E1 — изменяемое выражение lvalue, а E2 — выражение rvalue или список инициализации в фигурных скобках(с C++11)) абсолютно такое же, как поведение выражения E1 = E1 op E2, за исключением того, что выражение E1 вычисляется только один раз и ведет себя как отдельная операция относительно функций с неопределённой последовательностью вызовов (например, в f(a += b, g()), оператор += либо вообще не запускается, либо завершается, как видно изнутри g()).
При разрешении перегрузки против операторов пользователя для каждой пары A1 и A2, где A1 — арифметический тип (возможно с квалификатором volatile) и A2 — повышенный арифметический тип, в разрешении перегрузки участвуют следующие сигнатуры функций:
A1& operator*=(A1&, A2); | ||
A1& operator/=(A1&, A2); | ||
A1& operator+=(A1&, A2); | ||
A1& operator-=(A1&, A2); |
Для каждой пары I1 и I2, где I1 — целочисленный тип (возможно с квалификатором volatile) и I2 — повышенный целочисленный тип, в разрешении перегрузки участвуют следующие сигнатуры функций:
I1& operator%=(I1&, I2); | ||
I1& operator<<=(I1&, I2); | ||
I1& operator>>=(I1&, I2); | ||
I1& operator&=(I1&, I2); | ||
I1& operator^=(I1&, I2); | ||
I1& operator|=(I1&, I2); |
Для каждого типа объекта T с необязательными cv-квалификаторами в разрешении перегрузки участвуют следующие сигнатуры функций:
T*& operator+=(T*&, std::ptrdiff_t); | ||
T*& operator-=(T*&, std::ptrdiff_t); | ||
T*volatile & operator+=(T*volatile &, std::ptrdiff_t); | ||
T*volatile & operator-=(T*volatile &, std::ptrdiff_t); |
Пример
Отчеты об ошибках
Следующие отчеты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Применимо к | Поведение при публикации | Правильное поведение |
|---|---|---|---|
| CWG 1527 | C++11 | при присваивании объектам класса, правое операнд могло быть списком инициализации только тогда, когда присваивание определено пользователем оператором присваивания | устранено ограничение для пользовательского оператора присваивания |
| CWG 1538 | C++11 |
E1 = {E2} эквивалентно E1 = T(E2),( T — тип E1), это ввело преобразование стиля C | экв. E1 = T{E2} |
| P2327R1 | C++20 | битовые операторы составного присваивания для типов volatile были устаревшими, будучи полезными для некоторых платформ | они не устарели |
| CWG 2654 | C++20 | операторы составного присваивания для типов volatile были несогласованно устаревшими | ни один из них не устарел |
См. также
| Общие операторы | ||||||
|---|---|---|---|---|---|---|
| присваивание |
инкремент декремент | арифметические | логические | сравнения |
доступ к членам | другие |
|
|
|
|
|
|
| вызов функции |
a(...) |
||||||
| запятая | ||||||
a, b |
||||||
| условный | ||||||
a ? b : c |
||||||
| Специальные операторы | ||||||
|
|
||||||
| C documentation для Операторов присваивания |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/operator_assignment