Модель механизма диспетчеризации
Для лучшего понимания особенностей использования тэговых типов и свойств диспетчеризации вызовов операций, может оказаться полезным рассмотрение возможной модели реализации механизма диспетчеризации.
Следует подчеркнуть, что не смотря на достаточную реалистичность нашей модели, мы рассматриваем только возможную модель, сознательно опуская множество нюансов, а это значит, что реализация для какого-либо конкретного компилятора может не соответствовать этой модели.
Согласно нашей модели, подразумевается, что тэг - это указатель на таблицу диспетчеризации вызовов.
Каждый элемент такой таблицы содержит указатель на реализацию подпрограммы которая является примитивной операцией.
Диспетчеризация осуществляется путем выполнения косвенного вызова с помощью таблицы диспетчеризации, а необходимая примитивная операция выбирается как соответствующий индекс элемента в таблице диспетчеризации.
Таким образом, наша модель для рассмотренной ранее иерархии типов (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; |
Тогда, в этом описании содержится два примечательных факта:
реализацию функции The_Name. Следовательно, она будет унаследована от типа Child_1
Согласно нашей модели, вид тэга для типа Grand_Child_1_1 будет следующий:
-------------- Grand_Child_1_1'Tag ---> | The_Name |---> The_Name для Child_1 -------------- | New_Method |---> New_Method для 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.