Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Языки программирования / Литература по C++ / С.Липпман.С++ для начинающих.pdf
Скачиваний:
143
Добавлен:
31.05.2015
Размер:
5.55 Mб
Скачать

С++ для начинающих

722

Предопределенное назначение оператора нельзя изменить для встроенных типов. Например, не разрешается переопределить встроенный оператор сложения целых чисел

// ошибка: нельзя переопределить встроенный оператор сложения int

так, чтобы он проверял результат на переполнение.

int operator+( int, int );

Нельзя также определять дополнительные операторы для встроенных типов данных, например добавить к множеству встроенных операций operator+ для сложения двух массивов.

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

Предопределенные приоритеты операторов (см. раздел 4.13) изменить нельзя. Независимо от типа класса и реализации оператора в инструкции

x == y + z;

всегда сначала выполняется operator+, а затем operator==; однако помощью скобок порядок можно изменить.

Предопределенная арность операторов также должна быть сохранена. К примеру, унарный логический оператор НЕ нельзя определить как бинарный оператор для двух объектов класса String. Следующая реализация некорректна и приведет к ошибке

// некорректно: ! - это унарный оператор

bool operator!( const String &s1, const String &s2 )

{

return ( strcmp( s1.c_str(), s2.c_str() ) != 0 );

компиляции:

}

Для встроенных типов четыре предопределенных оператора ("+", "-", "*" и "&") используются либо как унарные, либо как бинарные. В любом из этих качеств они могут быть перегружены.

Для всех перегруженных операторов, за исключением operator(), недопустимы аргументы по умолчанию.

15.1.3. Разработка перегруженных операторов

Операторы присваивания, взятия адреса и оператор “запятая” имеют предопределенный смысл, если операндами являются объекты типа класса. Но их можно и перегружать. Семантика всех остальных операторов, когда они применяются к таким операндам, должна быть явно задана разработчиком. Выбор предоставляемых операторов зависит от ожидаемого использования класса.

С++ для начинающих

723

Начинать следует с определения его открытого интерфейса. Набор открытых функцийчленов формируется с учетом операций, которые класс должен предоставлять пользователям. Затем принимается решение, какие функции стоит реализовать в виде перегруженных операторов.

После определения открытого интерфейса класса проверьте, есть ли логическое соответствие между операциями и операторами:

isEmpty() становится оператором “ЛОГИЧЕСКОЕ НЕ”, operator!().

isEqual() становится оператором равенства, operator==().

copy() становится оператором присваивания, operator=().

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

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

Такой оператор одинаково хорошо поддерживает несколько различных интерпретаций. Безупречно четкое и обоснованное объяснение того, что делает operator+(), вряд ли устроит пользователей класса String, полагающих, что он служит для конкатенации строк. Если семантика перегруженного оператора неочевидна, то лучше его не предоставлять.

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

String s1( "C" );

String s2( "++" );

копирования:

s1 = s1 + s2;

// s1 == "C++"

Но этого недостаточно для поддержки составного оператора присваивания

s1 += s2;

Его следует определить явно, так, чтобы он поддерживал ожидаемую семантику. Упражнение 15.1

Почему при выполнении следующего сравнения не вызывается перегруженный оператор operator==(const String&, const String&):

"cobble" == "stone"

Упражнение 15.2