Инструменты пользователя

Инструменты сайта


bb:redbook:210

Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Следующая версия
Предыдущая версия
bb:redbook:210 [2016/03/31 15:30]
prospero78 создано
bb:redbook:210 [2020/10/29 07:08] (текущий)
Строка 7: Строка 7:
 ==== 2. Абстрактные типы ==== ==== 2. Абстрактные типы ====
 Абстрактные типы не могут иметь экземпляров. Казалось бы, парадокс: зачем нужно создавать типы данных, которые нельзя использовать? Оказывается, в этом есть смысл, если потом, на базе такого типа, будут создаваться другие типы, которые реализуют абстрактный тип. Они все будут разные, но поскольку в основе их лежит один базовый тип, те операции, которые определены для базового типа, вполне успешно могут быть использованы и в типах-потомках. Пример с неправильным использованием абстрактного типа приведён ниже: Абстрактные типы не могут иметь экземпляров. Казалось бы, парадокс: зачем нужно создавать типы данных, которые нельзя использовать? Оказывается, в этом есть смысл, если потом, на базе такого типа, будут создаваться другие типы, которые реализуют абстрактный тип. Они все будут разные, но поскольку в основе их лежит один базовый тип, те операции, которые определены для базового типа, вполне успешно могут быть использованы и в типах-потомках. Пример с неправильным использованием абстрактного типа приведён ниже:
-  +  MODULE Test_abstract; 
- +   
 +  TYPE 
 +      tVector = ABSTRACT RECORD 
 +          x: REAL; 
 +          y: REAL; 
 +      END; 
 +   
 +  VAR 
 +      v: tVector; 
 +   
 +  BEGIN 
 +  END Test_abstract.
 Компилятор прозрачно намекает, что так делать нельзя. Исправленный пример приводится ниже: Компилятор прозрачно намекает, что так делать нельзя. Исправленный пример приводится ниже:
-  +  MODULE Test_abstract; 
-  +   
- +  TYPE 
 +      tVector = ABSTRACT RECORD 
 +          x: REAL; 
 +          y: REAL; 
 +      END; 
 +   
 +      tMyVector1 = RECORD (tVector) 
 +          z: REAL; 
 +      END; 
 +   
 +      tMyVector2 = RECORD (tVector) 
 +          v: REAL; 
 +      END; 
 +   
 +  VAR 
 +      v: tMyVector1; 
 +      v1: tMyVector2; 
 +   
 +  BEGIN 
 +  END Test_abstract.
 Как видно из примера, вслед за типом tVector определяется тип-потомок tMyVector1, который в качестве базового использует абстрактный тип tVector. И такой тип уже не является абстрактным. В типе tMyVector1 добавляется поле z, которого нет в базовом типе. А в его родственнике по базовому типу, добавляется поле v, того же типа, что и z, но эти два типа уже обладают разным поведением, и это разные типы, хотя действия, определённые для базового типа tVector к ним обоим успешно применимы (в приведённом примере у базового типа методы не описаны). Как видно из примера, вслед за типом tVector определяется тип-потомок tMyVector1, который в качестве базового использует абстрактный тип tVector. И такой тип уже не является абстрактным. В типе tMyVector1 добавляется поле z, которого нет в базовом типе. А в его родственнике по базовому типу, добавляется поле v, того же типа, что и z, но эти два типа уже обладают разным поведением, и это разные типы, хотя действия, определённые для базового типа tVector к ним обоим успешно применимы (в приведённом примере у базового типа методы не описаны).
  
Строка 20: Строка 50:
 ==== 3. Расширяемые типы ==== ==== 3. Расширяемые типы ====
 Расширяемые типы чем-то похожи на абстрактные. Отличие состоит в том, что тип, описанный как расширяемый, может быть использован сразу: без необходимости наследовать его, прежде чем, создать экземпляр типа. Пример использования представлен ниже: Расширяемые типы чем-то похожи на абстрактные. Отличие состоит в том, что тип, описанный как расширяемый, может быть использован сразу: без необходимости наследовать его, прежде чем, создать экземпляр типа. Пример использования представлен ниже:
-  +  MODULE Test_extensible; 
- +   
 +  TYPE 
 +      tVector = EXTENSIBLE RECORD 
 +          x: REAL; 
 +          y: REAL; 
 +      END; 
 +   
 +      tMyVector1 = RECORD (tVector) 
 +          z: REAL; 
 +      END; 
 +   
 +  VAR 
 +      v: tVector; 
 +      v1: tMyVector1; 
 +   
 +  BEGIN 
 +  END Test_extensible.
 Абстрактный тип, также может расширяться в типах-потомках, но не может быть реализован. Далеко не всегда в качестве базового типа необохдимо использовать абстрактный тип. Да и гораздо чаще возникает необходимость расширить существующий тип, чем создавать тип с чистого листа. Стоить отметить, что раз введено такое семантическое свойство, как "расширяемый тип", очевидно, что без ключевого слова EXTENSIBLE тип расширить нельзя. Это поведение типа по умолчанию (как и сокрытие данных). [↑] Абстрактный тип, также может расширяться в типах-потомках, но не может быть реализован. Далеко не всегда в качестве базового типа необохдимо использовать абстрактный тип. Да и гораздо чаще возникает необходимость расширить существующий тип, чем создавать тип с чистого листа. Стоить отметить, что раз введено такое семантическое свойство, как "расширяемый тип", очевидно, что без ключевого слова EXTENSIBLE тип расширить нельзя. Это поведение типа по умолчанию (как и сокрытие данных). [↑]
   
Строка 29: Строка 75:
  
 Пример приводится ниже: Пример приводится ниже:
-  +  MODULE Test_limited; 
-  +   
- +  TYPE 
 +      tVector = LIMITED RECORD 
 +          x: REAL; 
 +          y: REAL; 
 +      END; 
 +   
 +      tMyVector1 = RECORD (tVector) 
 +          z: REAL; 
 +      END; 
 +   
 +  VAR 
 +      v: tVector; 
 +      v1: tMyVector1; 
 +   
 +  BEGIN 
 +  END Test_limited.
 Как видно в примере, при попытке его скомпилировать, возникла ошибка. Так как тип-потомок также должен наследовать атрибут ограничения. Как видно в примере, при попытке его скомпилировать, возникла ошибка. Так как тип-потомок также должен наследовать атрибут ограничения.
  
 Исправленный пример ниже: Исправленный пример ниже:
-  +  MODULE Test_limited; 
- +   
 +  TYPE 
 +      tVector = LIMITED RECORD 
 +          x: REAL; 
 +          y: REAL; 
 +      END; 
 +   
 +      tMyVector1 = LIMITED RECORD (tVector) 
 +          z: REAL; 
 +      END; 
 +   
 +  VAR 
 +      v: tVector; 
 +      v1: tMyVector1; 
 +   
 +  BEGIN 
 +  END Test_limited.
 И как видно, никаких вопросов у компилятора к программисту не возникает. [↑] И как видно, никаких вопросов у компилятора к программисту не возникает. [↑]
   
Строка 49: Строка 126:
  
 Примеры работы с записевыми типами не сильно отличаются от простых типов: Примеры работы с записевыми типами не сильно отличаются от простых типов:
-  +  MODULE Test_pointer; 
- +   
 +  IMPORT Log; 
 +   
 +  TYPE 
 +      tVector = ABSTRACT RECORD 
 +          x: REAL; 
 +          y: REAL; 
 +      END; 
 +   
 +      tPVector = POINTER TO RECORD (tVector) 
 +          z: REAL; 
 +      END; 
 +   
 +  VAR 
 +      v: tPVector; 
 +   
 +  PROCEDURE Start*; 
 +  BEGIN 
 +      Log.Real(v.x);Log.Real(v.y);Log.Real(v.z); 
 +      Log.Ln 
 +  END Start; 
 +   
 +  BEGIN 
 +      NEW (v); 
 +  END Test_pointer. 
 + 
 +  (!)Test_pointer.Start 
 +   
 +  компилируется "Test_pointer"   112   4 
 +  старый модуль Test_pointer выгружен 
 +  0.0 0.0 0.0
 В результате выполнения указанного фрагмента будут созданы базовый абстрактный тип tVector, который нельзя реализовать непосредственно. На его базе создаётся указательный тип tpVector, который вполне себе реализуем. При начале работе модуля через NEW создаётся экземпляр указательного типа tpVector, а в экспортируемой процедуре Start выводится значение всех полей. Как видно из вывода, все поля честно установлены в 0.0. В результате выполнения указанного фрагмента будут созданы базовый абстрактный тип tVector, который нельзя реализовать непосредственно. На его базе создаётся указательный тип tpVector, который вполне себе реализуем. При начале работе модуля через NEW создаётся экземпляр указательного типа tpVector, а в экспортируемой процедуре Start выводится значение всех полей. Как видно из вывода, все поля честно установлены в 0.0.
  
 Также следует отметить, что привязка методов к указательному типу выполняется несколько иначе, чем записевму типу: Также следует отметить, что привязка методов к указательному типу выполняется несколько иначе, чем записевму типу:
-  +  MODULE Test_pointer; 
- +   
 +  IMPORT Log; 
 +   
 +  TYPE 
 +      tPVector = POINTER TO RECORD 
 +          z: REAL; 
 +      END; 
 +   
 +  VAR 
 +      v: tPVector; 
 +   
 +  PROCEDURE (v: tPVector)Log(), NEW; 
 +  BEGIN 
 +      Log.Real(v.z); Log.Ln 
 +  END Log; 
 +   
 +  PROCEDURE Start*; 
 +  BEGIN 
 +      v.Log 
 +  END Start; 
 +   
 +  BEGIN 
 +      NEW (v); 
 +  END Test_pointer. 
 + 
 +  (!)Test_pointer.Start 
 +   
 +  компилируется "Test_pointer"   92   4 
 +  старый модуль Test_pointer выгружен 
 +  0.0
 Как видно из примера, при описании процедуры Log, при привязке метода к указательному типу, перед именем процедуры вместо  Как видно из примера, при описании процедуры Log, при привязке метода к указательному типу, перед именем процедуры вместо 
   
bb/redbook/210.1459427420.txt.gz · Последнее изменение: 2020/10/29 07:08 (внешнее изменение)