Урок 130. Введение в перегрузку операторов

   ⁄ 

 Обновлено 3 Апр 2018  ⁄ 

⁄   364

В уроке 102 мы узнали, что перегрузка функций обеспечивает механизм создания и выполнения вызовов функций с одним и тем же именем, но с разными параметрами. Это позволяет одной функции работать с несколькими разными типами данных (без необходимости придумывать уникальные имена для каждой из функций).

В C++ операторы реализованы в виде функций. Используя перегрузку функции оператора, вы можете определить собственные версии операторов, которые будут работать с разными типами данных (включая классы). Использование перегрузки функции для перегрузки оператора называется перегрузкой оператора.

Операторы как функции

Рассмотрим следующий пример:

Здесь компилятор будет использовать встроенную версию оператора плюс (+) для целочисленных операндов — эта функция добавит два целочисленных значения (a и b), и возвратит целочисленный результат. Когда вы видите выражение a + b, то думайте о нем, как о вызове функции operator+(a, b) (где operator+ является именем функции).

Теперь рассмотрим следующий фрагмент:

Компилятор также предоставит встроенную версию оператора плюс (+) для операндов типа double. Выражение m + p приведет к вызову функции operator+(m, p), а благодаря перегрузки оператора вызовется версия double (а не int).

Теперь рассмотрим, что произойдет, если мы попытаемся добавить два объекта класса:

Как вы думаете, какой будет результат? Наверное, вывод строки «Hello, World!»? Нет, так как класс Mystring является пользовательским типом данных, а компилятор не имеет встроенной версии operator+ для использования с операндами Mystring, поэтому результатом будет ошибка. Для того, чтобы сделать то, что мы хотим, нам придется написать свою версию функции operator+, и указать в ней алгоритм работы с операндами типа Mystring. То, как это сделать в коде, мы рассмотрим в следующем уроке.

Вызов перегруженных операторов

При обработке выражения, содержащего оператор, компилятор пользуется следующими алгоритмами действий:



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

  Если какой-либо из операндов является пользовательского типа данных (например, объект класса или типа перечисления), то компилятор будет искать версию оператора, которая работает с таким типом данных. Если не найдется ничего подходящего, то компилятор попытается конвертировать один или несколько операндов пользовательского типа данных в фундаментальные типы данных, чтобы, таким образом, он мог использовать соответствующий встроенный оператор. Если это не сработает – компилятор выдаст ошибку.

Ограничения в перегрузке операторов

Во-первых, почти любой существующий оператор в C++ может быть перегружен. Исключениями являются:

  тернарный оператор (?:);

  оператор sizeof;

  оператор разрешения области видимости (::);

  оператор выбора члена (.);

  указатель как оператор выбора члена (.*).

Во-вторых, вы можете перегружать только существующие операторы. Вы не можете создавать новые или переименовывать существующие. Например, вы не можете создать оператор ** для выполнения операции возведения в степень.

В-третьих, по крайней мере один из операндов перегруженного оператора должен быть пользовательского типа данных. Это означает, что вы не можете перегрузить operator+ для выполнения операции сложения значения int и значения double. Однако вы можете перегрузить operator+ для выполнения операции сложения значения int и объекта Mystring.

В-четвертых, изначальное количество операндов, поддерживаемых оператором, изменить невозможно. Т.е. с бинарным оператором используются только два операнда, с унарным – только один, с тернарным – только три.

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



Некоторые начинающие программисты пытаются перегрузить побитовый оператор XOR (^) для выполнения операции возведения в степень. Однако в C++ в оператора ^ приоритет ниже, чем в базовых арифметических операторов (+, -, *, /), что приведет к некорректной обработке выражений.

В математике, возведение в степень выполняется до выполнения базовых арифметических операций, поэтому 2 + 5 ^ 2 считается как 2 + (5 ^ 2) => 2 + 25 => 27. Однако в C++ в базовых арифметических операторов приоритет выше приоритета оператора ^, поэтому 2 + 5 ^ 2 выполнится как (2 + 5) ^ 2 => 7 ^ 2 => 49.

Вам нужно будет явно заключать в скобки часть с возведением в степень (например, 2 + (5 ^ 2)) каждый раз, когда вы хотите, чтобы она выполнялась первой, что очень легко забыть и, таким образом, наделать ошибок. Поэтому проводить подобные эксперименты мы не рекомендуем.

Примечание: В C++ для возведения в степень используется функция pow из заголовочного файла cmath. В примере выше с выполнением выражения 2 + 5 ^ 2 в коде C++ имеется в виду, что вы перегрузите побитовый оператор XOR (^) для выполнения операции возведения в степень.

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

Для чего использовать перегрузку операторов? Вы можете перегрузить оператор + для соединения объектов вашего класса String или для выполнения операции сложения двух объектов вашего класса Fraction (дробь). Вы можете перегрузить оператор << для вывода вашего класса на экран (или записи в файл). Вы можете перегрузить оператор равенства (==) для сравнения двух объектов класса. Подобные применения делают перегрузку операторов одной из самых полезных фич в C++, так как это упрощает процесс работы с классами и открывает новые возможности.

В следующих уроках этой главы мы рассмотрим перегрузку разных видов операторов.

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (3 оценок, среднее: 3,67 из 5)
Загрузка...
Подписаться на обновления:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

ПОДПИСЫВАЙТЕСЬ

НА КАНАЛ RAVESLI В TELEGRAM

@ravesli

ПОДПИСАТЬСЯ БЕСПЛАТНО