|
Программирование >> Инициализация объектов класса, структура
template <class T> class Queue { private: шаблон класса-члена template <class Type> class CL Type member; T mem; ... public: шаблон функции-члена template <class Iter> void assign( Iter first, Iter last ) while ( ! is empty() ) remove (); вызается Queue<T>:: remove() for ( ; first != last; ++first ) add( *first ); вызывается Queue<T>::add( const T & ) (Отметим, что шаблоны-члены не поддерживаются компиляторами, написанными до принятия стандарта C++. Эта возможность была добавлена в язык для поддержки реализации абстрактных контейнерных типов, представленных в главе 6.) Объявление шаблона-члена имеет собственные параметры. Например, у шаблона класса CL есть параметр Type, а у шаблона функции assign() - параметр Iter. Помимо этого, в определении шаблона-члена могут использоваться параметры объемлющего шаблона класса. Например, у шаблона CL есть член типа T, представляющего параметр включающего шаблона Queue. Объявление шаблона-члена в шаблоне класса Queue означает, что конкретизация Queue потенциально может содержать бесконечное число различных вложенных классов CL функций-членов assign(). Так, конкретизированный экземпляр Queue<int> включает Queue<int>::CL<char> вложенные типы: Queue<int>::CL<string> void Queue<int>::assign( int *, int * ) void Queue<int>::assign( vector<int>::iterator, и вложенные функции: vector<int>::iterator ) Для шаблона-члена действуют те же правила доступа, что и для других членов класса. Так как шаблон CL является закрытым членом шаблона Queue, то лишь функции-члены и друзья Queue могут ссылаться на его конкретизации. С другой стороны, шаблон функции assign() объявлен открытым членом и, значит, доступен во всей программе. template <class Iter> void assign( Iter first, Iter last ) удать все элементы из очереди for ( ; first != last; ++first ) add( *first ); на определение assign() : Вызываемая из assign() функция add() - это функция-член Queue<Type>::add() . Если Queue конкретизируется типом int, то у add() будет следующий прототип: void Queue<int>::add( const int &val ); Аргумент *first должен иметь тип int либо тип, которым можно инициализировать параметр-ссылку на const int. Преобразования типов допустимы. Например, если Шаблон-член конкретизируется при его использовании в программе. Например, int main() { конкретизация Queue<int> Queue<int> qi; конкретизация Queue<int>::assign( int *, int * ) int ai[4] = { 0, 3, 6, 9 }; qi.assign( ai, ai + 4 ); конкретизация Queue<int>::assign( vector<int>::iterator, vector<int>::iterator ) vector<int> vi( ai, ai + 4 ); qi.assign( vi.begin(), vi.end() ); assign() конкретизируется в момент обращения к ней из main() : Шаблон функции assign() , являющийся членом шаблона класса Queue, иллюстрирует необходимость применения шаблонов-членов для поддержки контейнерных типов. Предположим, имеется очередь типа Queue<int>, в которую нужно поместить содержимое любого другого контейнера (списка, вектора или обычного массива), причем его элементы имеют либо тип int (т.е. тот же, что у элементов очереди), либо приводимый к типу int. Шаблон-член assign() позволяет это сделать. Поскольку может быть использован любой контейнерный тип, то интерфейс assign() программируется в расчете на употребление итераторов; в результате реализация оказывается не зависящей от фактического типа, на который итераторы указывают. В функции main() шаблон-член assign() сначала конкретизируется типом int*, что позволяет поместить в qi содержимое массива элементов типа int. Затем шаблон-член конкретизируется типом vector<int>::iterator - это дает возможность поместить в очередь qi содержимое вектора элементов типа int. Контейнер, содержимое которого помещается в очередь, не обязательно должен состоять из элементов типа int. Разрешен любой тип, который приводится к int. Чтобы понять, почему это так, еще раз посмотрим class SmallInt { public: SmallInt( int ival = 0 ) : value( ival ) { } конвертер: SmallInt ==> int operator int() { return value; } ... private: int value; int main() { конкретизация Queue<int> Queue<int> qi; vector<SmallInt> vsi; заполнить вектор конкретизация Queue<int>::assign( vector<SmallInt>::iterator, vector<SmallInt>::iterator ) qi.assign( vsi.begin(), vsi.end() ); list<int*> lpi; заполнить список ошибка при конкретизации шаблона-члена assign(): нет преобразования из int* в int qi.assign( lpi.begin(), lpi.end() ); конвертер для приведения SmallInt к int: Первая конкретизация assign() правильна, так как существует неявное преобразование из типа SmallInt в тип int и, следовательно, обращение к add() корректно. Вторая же конкретизация ошибочна: объект типа int* не может инициализировать ссылку на тип const int, поэтому вызвать функцию add() невозможно. Для контейнерных типов из стандартной библиотеки C++ имеется функция assign() , которая ведет себя так же, как функция-шаблон assign() для нашего класса Queue. Любую функцию-член можно задать в виде шаблона. Это относится, в частности, к конструктору. Например, для шаблона класса Queue его можно определить следующим образом: воспользоваться классом SmiallInt из раздела 15.9, то содержимое контейнера, в котором хранятся элементы типа SmallInt, с помощью шаблона-члена assign() помещается в очередь типа Queue<int>. Это возможно потому, что в классе SmallInt имеется
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |