Присваивание самому себе должно работать
Определение operator=( )
должно всегда иметь следующую форму:
class class_name
{
const class_name operator=( const class_name r );
};
const class_name class_name::operator=( const class_name r )
{
if( this
!= r )
{
// здесь скопировать
}
return *this;
}
Аргумент, представляющий операнд источника данных, является ссылкой, чтобы избежать накладных расходов вызова по значению; это ссылка на константу, потому что аргумент не предназначен для модификации.
Эта функция возвращает ссылку, потому что она может это сделать. То есть вы могли бы удалить из объявления возвращаемой величины, и все бы работало прекрасно, но вы бы получили ненужный вызов конструктора копии, вынужденный возвратом по значению. Так как у нас уже есть объект, инициализированный по типу правой части (*this), то мы просто можем его вернуть. Даже если возврат объекта вместо ссылки в действительности является ошибкой для функции operator=(), компилятор просто выполнит то, что вы ему приказали. Здесь не будет сообщения об ошибке; и на самом деле все будет работать. Код просто будет выполняться более медленно, чем нужно.
Наконец, operator=()
должен возвращать ссылку на константу просто потому, что не хотите, чтобы кто-нибудь имел возможность модифицировать возвращенный объект после того, как произошло присваивание. Следующее будет недопустимым в случае возврата ссылки на константу:
(x =y) = z;
Причина состоит в том, что (x=y)
расценивается как возвращаемое значение функции operator=(), т.е. константная ссылка. Получателем сообщения =z
является объект, только что возвращенный от x=y. Тем не менее, вы не можете послать сообщение operator=()
константному объекту, потому что его объявление не имеет в конце const:
// НЕ ДЕЛАЙТЕ ЭТОГО В ФУНКЦИИ
// С ИСПОЛЬЗОВАНИЕМ operator=().
// |
// V
const class_name operator=( const class_name r ) const;
Компилятор должен выдать вам ошибку типа "не могу преобразовать ссылку на переменную в ссылку на константу", если вы попробуете (x=y)=z.
Другим спорным моментом в предыдущем коде является сравнение:
if( this
!= r )
в функции operator=(). Выражение:
class_name x;
// ...
x = x;
должно всегда срабатывать, и сравнение this с адресом входного правого аргумента является простым способом в этом убедиться. Имейте в виду, что многие алгоритмы полагают самоприсваивание безвредным, поэтому не делайте его особым случаем. Также имейте в виду, что самоприсваивание могло бы быть затушевано при помощи указателя, как в:
class_name array[10];
class_name *p = array;
// ...
*p = array[0];