Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 [ 26 ] 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105

у класса GenScatterHierarchy есть недостаток- он использует множественное наследование. Если размер кода очень важен, этот класс может стать непригодным, поскольку класс WidgetEventHandlег содержит три указателя на виртуальные таблицы", по одной для каждой конкретизации класса EventHandler. Если величина sizeof(EventHandler) равна 4 байт, то величина sizeof(WidgetEventHandlег) будет равна уже 12 байт, возрастая по мере добавления в список новых типов. Наиболее эффективно было бы объявлять все виртуальные функции внутри класса wi dgetEventHandl ег, правда, это не позволило бы генерировать код.

Линейная иерархия наследования позволяет разложить класс Wi dgetEventHandl ег на классы, по одному на каждую виртуальную функцию, как показано на рис. 3.5. При использовании простого наследования класс wi dgetEventHandl е г может иметь только один указатель на виртуальную таблицу, что максимально повышает его эффективность с точки зрения размера.

HandlerSctvllbar

OnEvent(scrl: ScrollBar&, eventid: int)

HandlerButton

OnEvent(btn: Button&, eventid : int)

HandlerWindow

OnEvent(wnd: Window&, eventid: int)

WidgetEventHandler

Рис. 3.5. Оптимальная no размеру структура класса WidgetEventHandler

Как создать механизм, автоматически генерирующий такую структуру? Для этого предназначен рекурсивный механизм, аналогичный классу GenScatterHierarchy. Однако есть одно отЛичие. Шаблонный класс, определенный пользователем, теперь должен принимать два шаблонных параметра. Один из них является текущим типом в списке типов, как и у класса GenScatterHierarchy, а второй - это базовый класс, от которого происходит конкретизация. Второй шаблонный параметр необходим, поскольку, как показано на рис. 3.5, код, определенный пользователем, теперь включается в середину иерархии классов, а не только в его корни (как это было в классе Gen-ScatterHierarchy).

Реализация не обязана использовать виртуальные таблицы, но большинство програм.ми-стов все же применяют их. Описание виртуальных таблиц дано в работе Lippman (1994).



Напишем рекурсивный шаблонный класс GenLinearHierarchy. Он похож на класс GenScatterHierarchy, но отношение наследования и шаблонный код, определенный пользователем, в нем обрабатываются иначе.

template <

class TList,

template <class AtomicType,class Base> class unit,

class Root = EmptyType класс EmptyType описан в главе 2

>

class GenLinearHierarchy;

template <

class Tl, class T2,

template <class, class> class unit, class Root

>

class GenLinearHierarchy<Typelist<Tl, Т2>, unit, Root> : public unit< Tl, GenLinearHierarchy<T2, unit, Root> >

template <

class T,

template <class, class> class unit, class Root

>

class GenLinearHierarchy<TYPELlST lCT), unit, Root> : public unit<T, Root>

Этот код немного сложнее, чем у класса GenScatterHierarchy, но структура иерархии класса GenLinearHierarchy намного проще. Следуя пословице "лучше один раз увидеть, чем сто раз услышать" ("image is worth 1,024 words"), посмотрим на рис. 3.6, на котором изображена иерархия классов, порожденная следующим кодом.

template <class т, class Base> class EventHandler : public Base {

public:

virtual void OnEventCT& obj, int eventid);

typedef GenLinearHierarchy <

TYPELIST 3(window, Button, ScrollBar), EventHandler

>

MyEventHandler;

В сочетании с классом EventHandler класс GewtLinearHierarchy определяет линейную иерархию простого наследования. Каждый узел в этой иерархии определяет одну чисто виртуальную функцию, как это предусмотрено для класса EventHandler. Следовательно, в классе EventHandler определены три виртуальные функции, как и требовалось. Класс GenLinearHierarchy выдвигает новое требование к своему шаблонному



параметру: класс unit (в нашем примере - класс EventHandler) должен получать второй шаблонный параметр и наследовать его свойства. В качестве компенсащ1и класс Gen-Li nearHierarchy выполняет сложную работу по генераш1и иерархии классов.

EmptyType

EventHandler<ScrollBar,EmptyType>

OnEventfscrl: ScrollBarS,, eventid: int)

GenLinearHierarchy<TYPELIST 1(ScrollBar),EventHandler>

EventHandter<Button,GenLinearHierarchy<TYPELIST i(ScrollBar),EventHandier»

OnEvent(btn: Button&, eventid: int)

GenLinearHieran:hy<TYPELIST2(Button, ScrollBar),EventHandler>

EventHandler<Window,GenLinearHierarchy<TYPELIST2(Button,ScrollBar),EventHandler»

OnEvent(wnd : Windows, eventid : int)

WidgetEventHandler

Рис. 3.6. Иерархия классов, порожденная шаблонным классом GenLinearHierarchy

Классы GenScatterHierarchy и GenLinearHierarchy прекрасно работают в тандеме. В большинстве случаев интерфейс можно генерировать с помощью класса GenScatterHierarchy, а реализацию- с помощью класса GenLinearHierarchy. Конкретные примеры использования этих двух генераторов приводятся в главах 9 и 10.

3.14. Резюме

Списки типов представляют собой важный метод обобщенного программирования. Они предоставляют создателям библиотек новые возможности: выражать и манипули-



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 [ 26 ] 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105