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() должна быть функцией-членом.


Назад  |  Вперёд


OtDiatlovaOU
К началу книги

Оформление и дизайн книги OtDiatlovaOU.
Вся книга, архив.