Лекции (1129116), страница 26

Файл №1129116 Лекции (Лекции) 26 страницаЛекции (1129116) страница 262019-05-11СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла (страница 26)

T1 y;

В этом случае, разрешено присваивание x=y, но неразрешено присваивание y=x. Тоже самое правило распространяется и на правила передачи параметров.

Что будет с динамическим типом объектов? Тут разные языки действуют по-разному. Их можно разделить на два класса – относительно статические языки и относительно динамические языки. В относительно статических языках (С++, Оберон) динамичность типа данных ограничена. В относительно динамических языках (Java, Delphi, Smalltalk) никаких ограничений на изменение типа нет.

Что происходит при таком присваивании? Есть два варианта: либо х меняет свой динамический тип, либо не меняет.

Чем же отличаются рассматриваемые нами языки? Объекты данных, под которые распределена память, не могут менять свой динамический тип. Т.е. динамически могут менять свой тип, в таких языках, как С++ и Оберон, только указатели и ссылки. Пусть типу Т соответствует указательный тип РТ, а типу Т1 соответствует тип РТ1. Тогда объекты типов РТ и РТ1 могут менять свой динамический тип. А объекты типов Т и Т1 свой динамический тип менять не могут. Это ограничение введено в язык из соображений эффективности, потому что иначе пришлось бы перераспределять память при каждом таком присваивании для смены динамического типа. Присваивание x=y в таких языках интерпретируется следующим образом.

О бъекту х присваивается только та часть объекта y, которая относится к типу Т.

Заметим, что обратное присваивание недопустимо, потому что тип Т1 богаче типа Т, к тому же, в этом случае, после присваивания, часть объекта y, относящаяся к типу Т, будет не определена. Т.е. динамический тип станет уже статического, а такого быть не может. То же самое относится и к передаче параметров. Если у нас есть функция F(T), то этой функции в качестве параметра можно передать объект типа Т1, потому что у него есть часть, относящаяся к типу Т. Если же есть функция G(T1), то понятно, что ей в качестве параметра передавать объект типа Т бессмысленно.

Рассмотрим, как такое присваивание интерпретируется в относительно динамических языках. Что общего между языком Delphi и Java? В частности то, что все объекты, объявленные как классы, являются на самом деле ссылками. Т.е. подход этих языков все равно близок к подходу С++ и Оберона, потому что там тоже можно менять динамический тип для ссылок и указателей. Но перед этим присваиванием программист обязан освободить память (в Java это сделает сборщик мусора), которую занимал объект х. Если же х имел пустое значение, то все в порядке. При этом перераспределения памяти не происходит, а в результате, х будет ссылаться на объект более богатого типа, чем тип объекта х. Т.е. х меняет свой динамический тип на тип Т1.

Теперь через объект х можно обращаться к полям типа Т1, но для этого нужно проверить динамический тип х. Для этого в Обероне была введена концепция динамической идентификации типа (для указателей и ссылок). Пусть есть процедура, параметром которой является ссылка на объект типа Т.

PROCEDURE P(VAR X:T);

Тогда в процедуре имеет смысл узнать динамический тип переменной Х, потому что он может отличаться от типа Т (т.е. тип объекта Х может быть производным от типа Т). Для этого есть две конструкции. Первая – это булевское выражение, которое имеет вид: t is T1, где t – это некоторое выражение, статический тип которого Т, а Т1 – это некоторый тип данных, производный (прямо или косвенно) от типа Т (иначе конструкция не имеет смысла и компилятор выдаст сообщение об ошибке). Эта проверка является истинной, если динамический тип данных выражения t либо совпадает с типом Т1, либо является производным от него. Т.е. если тип Т1 выведен из типа Т, а тип Т2 выведен из Т1, то проверка t is T1 будет истинной, если динамическим типом выражения t является Т1 или Т2. Структура любой переменной классового типа должна быть такова, чтобы иметь в себе информацию о динамическом типе.

Существует вторая конструкция – страж (guard) типа. Этот страж очень похож на преобразование типа и выглядит следующим образом: t(T1). Аналогично, t – это некоторое выражение, статический тип которого Т, а Т1 – это некоторый тип данных, производный от типа Т. Этот страж типа "говорит" следующее: "трактуй выражение t, как выражение типа T1. Т.е. если у типа Т есть свойство А, а у типа Т1 есть свойство В, то мы можем написать t.A, но не можем написать t.B, вместо этого нужно использовать страж типа: t(T1).B . Т.е. мы должны попросить компилятор проверить динамический тип t, и тогда можно обращаться к полям типа Т1.

IF t is T1 THEN //здесь выполняется проверка дин. типа

t(T1).B=… //здесь проверка дублируется и если все в порядке, //то происходит обращение к полю В, иначе – генерируется ошибка

В данном примере видно, что происходит лишняя проверка динамического типа, но к сожалению это необходимо для надежности. Есть модифицированная форма стража типа для сокращения записи и количества проверок:

WITH t:T1 DO //проверка выполняется только один раз

t.B=…

t.B=…

END;

Этот оператор внешне похож на оператор присоединения, который был в Паскале, но в Обероне это совсем другое.

В системе Delphi применяется такой же подход. Там тоже есть конструкция t is T1, при этом синтаксис и смысл этой конструкции совпадает с Обероном. Есть также преобразование t(T1), которое, в отличие от Оберона, не контролируется. Есть также два оператора присоединения – классический (with x do S), который позволяет обращаться к полям структуры непосредственно, и "обероновский" (with t as T1 do S), но здесь выполняется проверка типа, и если типы не совпадают, то генерируется исключительная ситуация, которую, по крайней мере, можно отловить.

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

Допустим, мы программируем в системе Windows в системе Delphi, и нам нужно написать часть кода, которая позволяет динамически менять шрифт. Есть класс TFont, который инкапсулирует семантику шрифта в системе Windows. Есть стандартный диалог, который позволяет выбирать параметры шрифта и выдает TFont. У нас есть самые различные редакторы, инкапсулированные разными классами: TEdit (однострочный редактор), TMemo (многострочный редактор), TRichEdit. Семантика изменения шрифта для всех этих редакторов различна. TEdit и TMem – простейшие редакторы, и они одношрифтовые, а TRichEdit – это более сложный редактор, в нем допускаются сегменты текста в различных шрифтах. Поэтому, реакция на установление шрифта в разных редакторах разная. Если у нас есть объект Х типа TEdit, то мы можем написать так: X.Font:=Fnt (где Fnt – шрифт, полученный из стандартного диалога Windows).

У TRichEdit тоже есть свойство Font, но этот шрифт работает только как шрифт по умолчанию, т.е. таким шрифтом будут рисоваться все символы, которые вы будете набирать после этого. А хочется выделить некий сегмент текста и изменить у него шрифт. В Delphi есть свойство ActiveControl, которое говорит, в каком поле (т.е. элементе управления (Control), но для краткости – поле) сейчас находится клавиатурный фокус. Нам нужно как раз узнать динамический тип этого поля, чтобы знать, каким образом менять шрифт. При этом, нам нужно учесть все возможные типы таких полей, потому что в неучтенных типах полей наша программа работать не будет. В тоже время, мы можем использовать иерархию классов в Delphi, в которой есть класс TWinControl, который инкапсулирует в себе базовую функциональность любого поля в системе Windows. Из TWinControl в частности выводится класс TCustomEdit (все эти классы содержат различные свойства, чтобы программисту не приходилось задавать их самому), из которого выводятся классы TEdit, TRichEdit, TMem и др. Благодаря этим классам, процедуру изменения шрифта написать очень просто:

procedure ChFont(Fnt:TFont);

var Edit : TCustomEdit; //Мы рассчитываем, что все редакторы будут выведены из TCustomEdit

begin

if ActiveControl is TCustomEdit then //ActiveControl – свойство главной формы –

begin // понятие, которое есть в Delphi

Edit:=TCustomEdit(ActiveControl);

if Edit is TRichEdit then

with Edit as TRichEdit do

begin

//Изменяем шрифт

end

else Edit.Font=Fnt;

end;

end;

Этот код хорош тем, что он работает для любых полей, выведенных из TCustomEdit, потому что у всех этих полей будет атрибут Font. Причем этот код будет работать и для тех классов, которые уже созданы после создания этого кода, – этого на традиционных языках программирования сделать нельзя. Эта возможность основана на концепции динамической идентификации типа.

Р ассмотрим аспект распределения памяти. Каким образом при наследовании (единичном) распределяется память? Есть две модели: линейная модель и цепная. Линейной модели придерживаются такие языки, как Delphi, Java и С++. Пусть из класса Т выведен класс Т1, а из Т1 выведен класс Т2. Тогда в линейной модели памяти объекты этих классов будут размещены, как показано на рисунке. Линейная модель памяти удобна тем, что всегда достаточно иметь адрес начала объекта. Поэтому преобразование типа t(T1) к начальному адресу добавляет смещение нужного объекта. Линейная модель памяти наиболее эффективна.

Но существует цепная модель памяти. Эта модель памяти используется в языках Оберон и Смолток. В цепной модели памяти объекты представляются в виде списка. Т.е. у объекта типа Т2 будет указатель на объект типа Т1, а у того – на объект типа Т. Кроме того, должно быть поле, хранящее динамический тип данного объекта (оно будет присутствовать в старшем классе, т.е. в данном случае в Т). Преобразование t(T1) проверяет динамический тип объекта, и осуществляет поиск по линейному списку нужной составляющей объекта.

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

Рассмотрим еще один пример на языке Оберон. Мы уже рассматривали пример, в котором был реализован контейнер (стек), содержащий объекты разных типов. Поэтому отпадает необходимость в статической параметризации. Организация гетерогенного стека была основана на типе Object:

Object = RECORD //Пустая запись, единственная роль которой

END; // служить корнем иерархии

PObject = POINTER TO Object; //указатель на объекты типа Object

//только указатели могут динамически менять тип в Обероне

….. //пишем стек, который работает с объектами типа Object

//в этом стеке можно сохранять объекты выведенные из Object

При работе с функцией стека POP мы должны смотреть, какой объект мы достали из стека, с помощью проверки типа (t is T). Работать с такими объектами можно с помощью стража типа (t(T1)). Но можно действовать несколько иначе. Допустим, что у нас есть некоторая совокупность графических объектов. Все графические объекты должны храниться в некотором контейнере, например, в линейном списке. Кроме того, все объекты обладают некоторыми общими свойствами, например, они умеют себя рисовать и перемещать. Мы уже писали костяк кода с помощью традиционного стиля программирования, и картина была неприглядной. Что же предлагает объектно-ориентированный стиль программирования?

TYPE Shape = POINTER TO NODE

NODE = RECORD //Звено линейного списка

NEXT:Shape;

END;

PROCEDURE Draw(P:Shape);

PROCEDURE Move(P:Shape; DX,DY:INTEGER);

TYPE Point = POINTER TO PointObj; //Точка

PointObj = RECORD(NODE)

X,Y:INTEGER;

END;

PROCEDURE DrawPoint(…);

PROCEDURE MovePoint (…);

TYPE Circle = POINTER TO CircleObj; //Окружность

CircleObj = RECORD(PointObj) // X,Y трактуется как центр окружности

R:INTEGER;

END;

PROCEDURE DrawCircle(…);

PROCEDURE MoveСircle(…);

Процедура рисования всех объектов будет выглядеть следующим образом:

PROCEDURE DrawAll(List:Shape)

BEGIN

WHILE List # NIL THEN

IF List is Point THEN DrawPoint(List(Point))

ELSEIF List is Circle THEN DrawCircle(List(Circle))

END;

List:=List.NEXT;

END;

END;

Вообще говоря, мы подобный код писали, рассматривая записи с вариантами. Каждый объект представлял собой запись с вариантами, и сущность этого объекта определялась дискриминантом. Структура программы, в сущности, была той же самой. Дал ли что-нибудь новый подход? Недостатком традиционного подхода было использование записи с вариантами, которая является ненадежным средством. Ничто не гарантирует соответствие дискриминанта и соответствующей области памяти.

Данный код очень похож на код в традиционном языке программирования, но он абсолютно надежен. Главным недостатком этого решения, является то, что при добавлении новых объектов, необходимо преобразовывать процедуру рисования. А подобных процедур в программе может быть очень много, и их все надо будет достроить. Т.е. код зависит от типов данных. Но это не недостаток объектно-ориентированного программирования – это недостаток соответствующей схемы. Мы можем написать более гибкий механизм, используя механизм т.н. обработчиков (Handler).

Лекция 22

В прошлый раз мы достаточно подробно разобрали типовую структуру ОО языков и вобщем-то ясно должно быть, что эта типовая структура является чистым расширением концепции уникальности типа, которую мы рассматривали в контексте обычных ЯП. У нас всегда есть возможность программировать на ОО языке в стиле, как мы программировали на хорешем процедурно-ориентированном языке типа Ada, Modula-2. Но, конечно, ОО языки предлагают существенно больше.

Характеристики

Тип файла
Документ
Размер
1,12 Mb
Материал
Тип материала
Высшее учебное заведение

Список файлов лекций

Свежие статьи
Популярно сейчас
Как Вы думаете, сколько людей до Вас делали точно такое же задание? 99% студентов выполняют точно такие же задания, как и их предшественники год назад. Найдите нужный учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
6264
Авторов
на СтудИзбе
317
Средний доход
с одного платного файла
Обучение Подробнее