Бьерн Страуструп - Язык программирования С++. Главы 5-8
Страница 63. Вызов функции



7.8 Вызов функции

 Вызов функции, т.е. конструкцию выражение(список-выражений), можно
 рассматривать как бинарную операцию, в которой выражение является
 левым операндом, а список-выражений - правым. Операцию вызова
 можно перегружать как и другие операции. В функции operator()()
 список фактических параметров вычисляется и проверяется по типам
 согласно обычным правилам передачи параметров. Перегрузка операции
 вызова имеет смысл прежде всего для типов, с которыми возможна
 только одна операция, а также для тех типов, одна из операций над
 которыми имеет настолько важное значение, что все остальные в
 большинстве случаев можно не учитывать.
      Мы не дали определения итератора для ассоциативного массива
 типа assoc. Для этой цели можно определить специальный класс
 assoc_iterator, задача которого выдавать элементы из assoc в некотором
 порядке. В итераторе необходимо иметь доступ к данным, хранимым
 в assoc, поэтому он должен быть описан как friend:

            class assoc {
            friend class assoc_iterator;
                pair* vec;
                int max;
                int free;
            public:
                assoc(int);
                int& operator[](const char*);
            };

  Итератор можно определить так:

            class assoc_iterator {
               const assoc* cs;   // массив assoc
               int i;             // текущий индекс
            public:
               assoc_iterator(const assoc& s) { cs = &s; i = 0; }
               pair* operator()()
                 { return (i<cs->free)? &cs->vec[i++] : 0; }
            };

Массив assoc объекта assoc_iterator нужно инициализировать, и при каждом
обращении к нему с помощью операторной функции () будет возвращаться
указатель на новую пару (структура pair) из этого массива. При достижении
конца массива возвращается 0:

            main()  // подсчет числа вхождений во входной
                    // поток каждого слова
            {
              const MAX = 256;  // больше длины самого длинного слова
              char buf[MAX];
              assoc vec(512);
              while (cin>>buf) vec[buf]++;
              assoc_iterator next(vec);
              pair* p;
              while ( p = next(vec) )
                  cout << p->name << ": " << p->val << '\n';
            }

      Итератор подобного вида имеет преимущество перед набором
функций, решающим ту же задачу: итератор может иметь собственные
частные данные, в которых можно хранить информацию о ходе итерации.
Обычно важно и то, что можно одновременно запустить сразу несколько
итераторов одного типа.
      Конечно, использование объектов для представления итераторов
непосредственно никак не связано с перегрузкой операций. Одни
предпочитают использовать тип итератора с такими операциями, как
first(), next() и last(), другим больше нравится перегрузка операции
++ , которая позволяет получить итератор, используемый как указатель
(см. $$8.8). Кроме того, операторная функция operator() активно
используется для выделения подстрок и индексации многомерных массивов.
      Функция operator() должна быть функцией-членом.

 
« Предыдущая статья   Следующая статья »