Введение в язык Си++

         

Обобщенные Классы


Очевидно, можно было бы определить списки других типов (classdef*, int, char* и т.д.) точно так же, как был определен класс nlist: простым выводом из класса slist. Процесс определения таких новых типов утомителен (и потому чреват ошибками), но с помощью макросов его можно "механизировать". К сожалению, если пользоваться стандартным C препроцессором (#4.7 и #с.11.1), это тоже может оказаться тягостным. Однако полученными в результате макросами пользоваться довольно просто.

Вот пример того, как обобщенный (generic) класс slist, названный gslist, может быть задан как макрос. Сначала для написания такого рода макросов включаются некоторые инструменты из :

#include "slist.h"

#ifndef GENERICH #include #endif

Обратите внимание на использование #ifndef для того, чтобы гарантировать, что в одной компиляции не будет включен дважды. GENERICH определен в .

После этого с помощью name2(), макроса из для конкатенации имен, определяются имена новых обобщенных классов:

#define gslist(type) name2(type,gslist) #define gslist_iterator(type) name2(type,gslist_iterator)

И, наконец, можно написать классы gslist(тип) и gslist_iterator(тип):

#define gslistdeclare(type) \ struct gslist(type) : slist { \ int insert(type a) \ { return slist::insert( ent(a) ); } \ int append(type a) \ { return slist::append( ent(a) ); } \ type get() { return type( slist::get() ); } \ gslist(type)() { } \ gslist(type)(type a) : (ent(a)) { } \ ~gslist(type)() { clear(); } \ }; \ \ struct gslist_iterator(type) : slist_iterator { \ gslist_iterator(type)(gslist(type) a) \ : ( (slist)s ) {} \ type operator()() \ { return type( slist_iterator::operator()() ); } \ }

\ на конце строк указывает , что следующая строка является частью определяемого макроса.

С помощью этого макроса список указателей на имя, аналогичный использованному раньше классу nlist, можно определить так:

#include "name.h"

typedef name* Pname; declare(gslist,Pname); // описать класс gslist(Pname)

gslist(Pname) nl; // описать один gslist(Pname)

Макрос declare (описать) определен в . Он конкатенирует свои параметры и вызывает макрос с этим именем, в данном случае gslistdeclare, описанный выше. Параметр имя типа для declare должен быть простым именем. Используемый метод макроопределения не может обрабатывать имена типов вроде name*, поэтому применяется typedef.

Использования вывода класса гарантирует, что все частные случаи обобщенного класса разделяют код. Этот метод можно применять только для создания классов объектов того же размера или меньше, чем базовый класс, который используется в макросе. gslist применяется в



Содержание раздела