Бьерн Страуструп - Язык программирования С++. Главы 8-10 - Задание реализации с помощью параметров шаблона

ОГЛАВЛЕНИЕ


8.7.1 Задание реализации с помощью параметров шаблона

В контейнерных классах часто приходится выделять память. Иногда бывает необходимо (или просто удобно) дать пользователю возможность выбирать из нескольких вариантов выделения памяти, а также позволить ему задавать свой вариант. Это можно сделать несколькими способами. Один из способов состоит в том, что определяется шаблон типа для создания нового класса, в интерфейс которого входит описание соответствующего контейнера и класса, производящего выделение памяти по способу, описанному в $$6.7.2:
        template<class T, class A> class Controlled_container
            : public Container<T>, private A {
            // ...
            void some_function()
            {
              // ...
              T* p = new(A::operator new(sizeof(T))) T;
              // ...
            }
            // ...
       };
Шаблон типа здесь необходим, поскольку мы создаем контейнерный класс. Наследование от Container<T> нужно, чтобы класс Controlled_container можно было использовать как контейнерный класс. Шаблон типа с параметром A позволит нам использовать различные функции размещения:
      class Shared : public Arena { /* ... */ };
      class Fast_allocator { /* ... */ };

      Controlled_container<Process_descriptor,Shared> ptbl;

      Controlled_container<Node,Fast_allocator> tree;

      Controlled_container<Personell_record,Persistent> payroll;
Это универсальный способ предоставлять производным классам содержательную информацию о реализации. Его положительными качествами являются систематичность и возможность использовать функции-подстановки. Для этого способа характерны необычно длинные имена. Впрочем, как обычно, typedef позволяет задать синонимы для слишком длинных имен типов:
       typedef
       Controlled_container<Personell_record,Persistent> pp_record;

       pp_record payroll;
Обычно шаблон типа для создания такого класса как pp_record используют только в том случае, когда добавляемая информация по реализации достаточно существенна, чтобы не вносить ее в производный класс ручным программированием. Примером такого шаблона может быть общий (возможно, для некоторых библиотек стандартный) шаблонный класс Comparator ($$8.4.2), а также нетривиальные (возможно, стандартные для некоторых библиотек) классы Allocator (классы для выделения памяти). Отметим, что построение производных классов в таких примерах идет по "основному проспекту", который определяет интерфейс с пользователем (в нашем примере это Container). Но есть и "боковые улицы", задающие детали реализации.