Двойная диспетчеризация
Бывают случаи, когда при описании в одном пакете двух различных тэговых типов возникает желание описать подпрограмму которая принимает параметры обоих тэговых типов.
В подобной ситуации получается, что такая подпрограмма будет считаться примитивной операцией для обоих типов.
Однако, компилятор должен иметь какой-нибудь способ определения того, какой параметр использовать для диспетчеризации.
Чтобы, яснее представить суть подобной проблемы, рассмотрим следующий (не корректный!!!) пример
type Message_Type is
tagged record . . . end record; type Output_Device is tagged record . . . end record; procedure Put (M : in Message_Type; D : in Output_Device); -- записать сообщение M в устройство вывода D (не допустимо!!!) . . . |
На первый взгляд, идея выглядит достаточно логично, при наличии различных типов устройств вывода иметь процедуру, которая позволяет выдать определенного типа сообщение в устройство вывода определенного типа.
Каждый тип сообщения может переопределить соответствующим образом процедуру вывода Put для того чтобы осуществить свой вывод необходимым образом.
Каждый тип устройства вывода переопределяет процедуру Put
с целью использования средств предоставляемых устройством вывода.
Однако, при вызове процедуры Put становится не понятным какую версию этой процедуры необходимо использовать, ту которая определена в типе, производном от типа Message_Type, или ту которая определена в типе, производном от типа Output_Device.
Ада решает эту проблему очень просто: использование подпрограмм которые являются примитивными операциями для двух (и более) тэговых типов, подобно процедуре Put, - не допускается.
Следовательно, необходимо изменить описание процедуры таким образом, чтобы она была примитивной операцией только для одного типа.
Примером такой модификации может служить следующее:
procedure Put (M : in Message_Type; D : in Output_Device'Class); |
Теперь, параметр D больше не имеет тип Output_Device, а значит, процедура Put больше не является примитивной операцией для типа Output_Device.
Однако, внутри процедуры, значение Output_Device'Class
приведет к осуществлению диспетчеризации в случае вызова примитивной операции для типа Output_Device.
Подобный прием называют двойной диспетчеризацией.
Например, предположим, что тип Output_Device имеет следующую примитивную операцию:
procedure Write_Output (D : in Output_Device; S : in String); |
procedure Put (M : in Message_Child_Type; D : in Output_Device'Class) is begin Put (Message_Type(M), D); -- вызов версии Put предка . . . Write_Output (D, ... ); -- отображение данных сообщения . . . end Put; |
Это приведет к тому, что отображение данных сообщения будет осуществлено с помощью процедуры Write_Output, реализация которой будет выбрана в результате диспетчеризации.