Урок №139. Перегрузка оператора ()

  Юрий  | 

    | 

  Обновл. 23 Июн 2019  | 

 6466

 ǀ   4 

Все операторы, перегрузку которых мы рассматривали до сих пор, позволяли нам самостоятельно определять тип параметров в функции перегрузки оператора, но не их количество. Например, оператор == всегда принимает два параметра, тогда как оператор ! всегда принимает один параметр. Оператор () является особенно интересным, поскольку позволяет изменять как тип параметров, так и их количество.

Но следует помнить о двух вещах:

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

   Во-вторых, в не объектно-ориентированном C++ оператор () является оператором вызова функции. В случае с классами перегрузка круглых скобок выполняется в методе operator()(){} (в объявлении функции перегрузки находятся две пары круглых скобок).

Перегрузка оператора ()

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

Матрицы являются ключевой концепцией в линейной алгебре и часто используются в геометрическом моделировании и в 3D-графике. Всё, что вам нужно знать сейчас — это то, что класс Matrix является двумерным массивом (5 на 5 типа double).

В уроке о перегрузке оператора индексации мы использовали оператор [] для прямого доступа к элементам закрытого одномерного массива. Здесь же нам нужен доступ к элементам двумерного массива. Поскольку оператор [] ограничен лишь одним параметром, то его функциональности недостаточно для доступа к двумерному массиву.

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

Результат выполнения программы выше:

3.6

Выполним перегрузку оператора () ещё раз, но уже без использования каких-либо параметров:

Результат выполнения программы выше:

0

Поскольку оператор () является настолько гибким, то может возникнуть соблазн использовать его для самых разных целей. Однако, это настоятельно не рекомендуется, поскольку оператор () не является очень информативным и зачастую может быть не понятно, что он делает. В примере выше функцию очистки массива лучше было бы записать в виде метода clear() или erase(), поскольку matrix.erase() выглядит намного информативнее, нежели просто matrix().

Функторы в C++


Перегрузка оператора () используется в реализации функторов (или ещё «функциональных объектов») — классы, которые работают как функции. Преимущество функтора над обычной функцией заключается в том, что функторы могут хранить данные в переменных-членах (поскольку они сами являются классами). Вот пример использования простого функтора:

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

Вы можете спросить: «Зачем использовать класс, если всё можно реализовать и через обычную функцию со статической локальной переменной?». Можно сделать и через static, но, поскольку функции представлены только одним глобальным экземпляром (т.е. нельзя создать несколько объектов функции), то использовать эту функцию мы можем только для выполнения чего-то одного за раз. С помощью функторов мы можем создать любое количество отдельных функциональных объектов, которые нам нужны, и использовать их одновременно.

Заключение

Перегрузка оператора () с двумя параметрами используется для получения доступа к двумерным массивам или для возврата подмножества одномерного массива (два параметра будут конкретизировать условия отбора элементов подмножества). Всё остальное лучше реализовать через отдельные методы с более информативными названиями, нежели через перегрузку оператора ().

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

Тест


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

Подсказка №1: Вы можете использовать индекс массива [] для доступа к отдельным символам строки.

Подсказка №2: Вы можете использовать оператор += для добавления чего-либо к строке.

Следующий фрагмент кода:

Должен производить следующий результат:

world!

Ответ

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

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (27 оценок, среднее: 4,85 из 5)
Загрузка...

Комментариев: 4

  1. Аватар Валерий:

    По тесту. А в реализации оператора () выход на границы строки проверять разве не нужно? Странно.
    Вызов string(7, 7) еще проходит. А вот string(7, 8) — уже вылетает.
    На мой взгляд реализация

    будет более правильной.
    Возвращаем не более len символов начиная со start. Если строка закончилась раньше — возвращаем до конца строки.
    Либо можно вычислить минимум из требуемого кол-ва и размера "хвостика" строки и цикл ограничивать этим значением.

    1. Аватар teezbeGood:

      Тоже так решил, но с точки зрения красоты, чей вариант лучше не знаю)

  2. Аватар Александр:

    @@@
    Поскольку оператор [] ограничен лишь одним параметром, то его функциональности недостаточно для доступа к двумерному массиву.
    @@@
    почему недостаточно?
    мы можем возвращать указатель на начало "строки" двумерного массива

    обращение к двумерному массиву:

  3. Аватар kmish:

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

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