Ада-95. Компилятор GNAT

       

Модель механизма диспетчеризации


Для лучшего понимания особенностей использования тэговых типов и свойств диспетчеризации вызовов операций, может оказаться полезным рассмотрение возможной модели реализации механизма диспетчеризации.

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

Согласно нашей модели, подразумевается, что тэг - это указатель на таблицу диспетчеризации вызовов.

Каждый элемент такой таблицы содержит указатель на реализацию подпрограммы которая является примитивной операцией.

Диспетчеризация осуществляется путем выполнения косвенного вызова с помощью таблицы диспетчеризации, а необходимая примитивная операция выбирается как соответствующий индекс элемента в таблице диспетчеризации.

Таким образом, наша модель для рассмотренной ранее иерархии типов (Root, Child_1, Child_2 и Grand_Child_2_1) будет иметь следующий вид:

------------ Root'Tag ---> | The_Name |---> The_Name для Root ------------

------------ Child_1'Tag ---> | The_Name |---> The_Name для Child_1 ------------

------------ Child_2'Tag ---> | The_Name |---> The_Name для Child_2 ------------

------------ Grand_Child_2_1'Tag ---> | The_Name |---> The_Name для Grand_Child_2_1 ------------

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

Базовый адрес каждой таблицы соответствует значению тэга и содержится в значении надклассового объекта.

Примечательно также, что в таблицах диспетчеризации не содержатся указатели на надклассовые операции (подобные процедуре Show), поскольку они не являются диспетчеризуемыми операциями.

Таким образом, при динамическом связывании во время выполнения программы, на основе информации о тэге объекта осуществляется выбор соответствующей таблицы диспетчеризации.




Далее, по выбранной таблице, осуществляется косвенный вызов подпрограммы, для которой индекс в таблице соответствует требуемой примитивной операции.

Для лучшей демонстрации этой идеологии, предположим теперь, что мы решили описать новый тип Grand_Child_1_1, производный от типа Child_1, следующим образом:

with Simple_Objects; use Simple_Objects;

package Simple_Objects_New is

type Grand_Child_1_1 is new Child_1 with null record;

procedure New_Method (Self: in Grand_Child_1_1); procedure New_Method_Call (Self: in Grand_Child_1_1'Class); . . .

end Simple_Objects_New;

Дополнительно предположим, что далее в пакете Simple_Objects_New описываются типы, производные от типа Grand_Child_1_1, и то, что реализация надклассовой процедуры New_Method_Call выполняет диспетчеризуемый вызов процедуры New_Method.

Тогда, в этом описании содержится два примечательных факта:

  • Мы сознательно не определили для типа Grand_Child_1_1

    реализацию функции The_Name. Следовательно, она будет унаследована от типа Child_1

  • Описание типа Grand_Child_1_1 определяет новую примитивную диспетчеризуемую операцию - процедуру New_Method.

    Согласно нашей модели, вид тэга для типа Grand_Child_1_1 будет следующий:

    -------------- Grand_Child_1_1'Tag ---> | The_Name |---> The_Name для Child_1 -------------- | New_Method |---> New_Method для Grand_Child_1_1 --------------

    Из данной иллюстрация видно, что поскольку тип Grand_Child_1_1

    не имеет собственной реализации функции The_Name, то таблица диспетчеризации, которая соответствует его тэгу, содержит указатель на реализацию функции The_Name

    для его предка, типа Child_1.

    Таким образом, вызов процедуры Show, для типа Grand_Child_1_1, осуществит вызов унаследованной от типа Child_1 реализации функции The_Name

    (в соответствии с индексом в таблице диспетчеризации).

    Примечательно также, что описание новой примитивной операции (процедура New_Method) обусловило появление нового элемента в таблице диспетчеризации для типа Grand_Child_1_1.


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