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

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

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

Тот код, который мы написали для процедуры DrawAll несомненно нехорошим стилем ООП. В частности, то, что мы написали, очень похоже на то, что пишется не в ОО языках за исключением наследования. Нехорошесть заключается в том, что для введения нового типа данных (прямоугольника или отрезка) нужно было бы перелопачивать весь код. Мало того, в нем содержалась ошибка. Если бы иерархия была такая:

Shape

Point

Circle

Line

то все было бы нормально, но в написанном варианте код не работал. Основная идея была в переключателе:

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

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

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

Shape

Point

Circle

Line

очевидно, что в этом случае будет ошибка – всегда будет рисоваться точка.

Вирт предлагает другую методологию реализации подобных вещей. Он предлагает использовать handler’ы (обработчики). Обработчик – это некое поле данных, тип которого – процедурный. Чтобы не писать переключатель, который в зависимости от типа вызывает нужную процедуру, мы вставляем некоторое поле процедурного типа (чем-то это напоминает событийно-ориентированное программирование). Что общего имеют все объекты, выведенные из Shape (неважно как – непосредственно или через промежуточные типы)? Во-первых, они будут обладать указателями на следующий объект списка, потом, они умеют себя отрисовывать и передвигать. Мы пишем:

Nale = RECORD

Next: Shape;

DrawProc = PROCEDURE(Shape); // вводим типы обработчиков

MoveProc = PROCEDURE(Shape; DX,DY: INTEGER);

Draw: DrawProc; // вводим сами обработчики

Move: MoveProc;

END;

Как тогда мы будем расширять иерархию? Вот так:

Point_Obj = RECORD(Shape)

x,y: integer;

END;

Теперь мы должны написать методы Move и Draw.

Процедура для отрисовк должна по профилю совпадать с DrawProc:

PROCEDURE DrawPoint(this: Shape);

BEGIN

...

END DrawPoint;

После чего мы обязательно должны написать процедуру (фактически, это конструктор):

PROCEDURE InitPoint(this: Point; x,y: integer);

begin

this.x:=x;

this.y:=y;

this.Draw:=DrawPoint; //инициализация соответствующих обработчиков

this.Move:=MovePoint;

...

END InitPoint;

Теперь, как только мы создаем новый экземпляр объекта:

VAR P: Point;

Мы делаем:

new (P); //выделяем память

InitPoint(P,1,2); //инициализируем

List.Add(P); //добавляем в список

И так мы должны делать для каждой, в данном случае, графической фигуры, которую хотелось бы использовать. Это можно оформить в виде отдельного модуля и по-тихоньку добавлять.

Как же будет выглядеть теперь процедура отрисовки всех объектов? Следующим образом:

PROCEDURE DrawAll(List;Shape);

BEGIN

WHILE List # NIL DO

List.Draw(List);

List:=List.Next;

END;

END DrawAll;

Эта процедура будет работать для любых типов данных, производных от Shape. Соответственно, нам следует всего лишь добавлять новые объекты и определять в них процедуры Init, Draw и Move. При этом DrawAll никак не изменится, даже в двоичном коде. Это и есть нормальное наследование.

Почему DrawPoint работала с типом Shape? Ведь, возможно, правильнее было бы написать:

PROCEDURE DrawPoint(this: Point);

Но дело в том, что если мы сделаем подобное ослабление в системе типов, то есть не будем требовать точного соответствия handler’ов, то придем к очень плохой ситуации. А именно, когда мы пишем некую процедуру, например, DrawPoint, у которой параметр “this: Point”, то для чего введены статические типы данных помимо динамических? Статические типы гарантируют, что фактический параметр обязательно будет обладать свойствами объекта Point. Причем правила согласования в компиляторе требуют, что фактический параметр был либо типа Point, либо производным от него. Если мы разрешим

DrawPoint (this:Point)

вставать на место DrawProc,то получится беда, а именно, в тот момент, когда будет передан объект типа Point в процедуру

DrawCircle (this: Circle);

а Point, это не Circle. В результате, мы получим ошибку защиты памяти.

Поэтому профиль обработчиков должен совпадать точно. Очевидно, что и DrawPoint и любая другая процедура должны начинаться, как:

PROCEDURE DrawPoint(this: Shape);

BEGIN

WITH this(Point) DO // этот страж типа должен быть обязательно

...

END DrawPoint;

Если тип будет передан неправильно, то программа выдаст ошибку.

Вот такой стиль программирования можно уже назвать объектно-ориентированным. Для этого мы ввели динамическое связывание методов (handler’ы).

Очередной раз стоит заметить, что ООП к ОО языкам отношение имеет не самое большое. Как уже говорилось, можно с успехом объектно программировать и на обычных языках. Например, наследование можно реализовать, как вложенность структуры:

Core=>Primitive

struct {

Core core_part;

Primitive_part prim_part;

}

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

Естественно, что по-настоящему объектным язык становится лишь тогда, когда появляется возможность надежной динамической привязки методов. Это то, что называется в терминологии C++ виртуальными методами доступа. Интересно, что в Oberon-2 появилось тоже самое.

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

C++

Пусть у нас есть класс T. Тогда класс наследник описывается как:

class T1: <спецификатор доступа> T {

...

}

И сразу нам приходится начать обсуждать проблемы доступа в C++. Поле <спецификатор> может принимать значения

  • private (он же по умолчанию, если ничего не указано)

  • public

  • protected

Также эти спецификаторы могут употребляться и внутри описания класса:

class T {

public:

int a;

private int b;

protected int c;

...

}

Стоит повторить, что

public:

объект доступен там же, где и экземпляр класса

private:

объект доступен только изнутри для функций-членов класса с учетом «друзей»

так как b объявлена как private, то функции-члены класса T1 уже не могут обращаться к b. Приватность – самое жесткое ограничение доступа

protected:

доступ к таким объектам разрешен только из функций-членов своего класса и наследников

Когда мы указываем спецификатор перед родительским классом, мы указываем усилитель доступа. Пусть класс T1 выглядит как:

class T1: public T {

int d, e;

...

}

Если мы укажем «public T», как в примере, то это означает, что права доступа для членов родительского класса не изменяются. Если написать “protected T”, это будет означать, что все public объекты в T являются protected в T1. Если же написать “private T”, то все члены T (public и protected) станут private в T1.

Заметим, что эти спецификаторы только усиливают защищенность, но не уменьшают.

Следует обратить внимание, что “private T” запрещает доступ из T1 к объектам T.

Также, если мы объявим:

class T2: public T1 {

g() {a=1; b=2;c=3}; // здесь возникнет ошибка, если “class T1: private T”

}

Еще такое замечание. Мы говорим о правах доступа и управлении доступом. А есть альтернативный подход: можно управлять доступом, а можно управлять видимостью. Чем отличаются эти два понятия? Если в языке реализовано управление доступом, то это означает, что если мы объявили где-то какой-то элемент, то он всегда виден, а вот доступа к нему может не быть. И здесь есть некий ньюанс, он достаточно тонкий, и мы еще будем о нем говорить.

Заметим, что наследование допускает такие вещи, как, например, перекрытие полей, операций. Например, в T1 можно объявить свое поле a, в отличе от T, где тоже есть a. Непосредственный доступ можно получить путем точного указания класса, например, T1::a.

Java

В Java синтаксис немного другой, но суть такая же:

class T1 extends T {

...

}

Заметим, что в Java при наследовании нельзя усилить защищенность объектов класса-родителя, создатели языка посчитали это избыточностью.

В Java есть некоторые отличия от C++. В частности, спецификатор доступа надо указывать перед каждым полем, тогда как в C++ они работают как переключатели – один спецификатор покрывает все объекты до следующего спецификатора.

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

package имя_пакета

use имя_пакета

Спецификаторы public и private в Java означают то же , что и в C++. А вот с protected есть некоторая тонкость – protected означает, что нельзя использовать извне класса, но можно использовать объект из унаследованного класса. Рассмотрим ситуацию

class T{

protected int a;

}

Пусть T1 и T2 – наследники T.

Можно ли писать:

f( T2 t) {t.a}; ?

Нет. А в C++ можно.

Delphi

В Delphi все очень похоже на C++ и Java, только там есть еще один спецификатор - published. Это связано исключительно с самим языком Delphi, так как в нем есть такая отличительная черта, как свойства (Property). Property ничего нового не добавляет в язык, но делает его удобнее. Все пошло с языка Visual Basic 3.0, там были стандартные компоненты, у которых были три атрибута:

  • методы

  • свойства

  • события

Например, если компонента визуальная, то у нее можно было написать:

Comp.Width=10;

Comp.Show=true;

События – это те события (нажатие мышкой, например), на которые реагирует данный компонент. Понято, что метод – это то, как он реагирует. А вот что есть Свойство? Просто переменной это назвать нельзя, так как присваивание

Comp.Width=10;

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

Просто оказалось, что есть наборы операций, которые с точки зрения программиста и визуализации (например) выглядят, как изменение одного числа или параметра. В C++ так просто сделать нельзя. Но с точки зрения прикладного программиста подход Delphi весьма удобен. Property определяется следующим образом:

type MyComp= class(TWinControl)

FMyprop: integer;

property MyProp: read FMyProp; //выполнится при чтении Property

write FMyProp; // выполнится при записи в Property

FMyProp2: integer;

procedure SetMyProp2(...); //определяется процедура для работы с Property

property MyProp2: read FMyProp2;

write SetMyProp2;

end;

C:MyComp;

C.MyProp:=3;

C.MyProp2:=10;

Очевидно, что это очень удобно, особенно при визуальной разработке приложений.

Интересно, что события в Delphi тоже реализованы, как Property, значения которых – процедурный тип, правда, немного необычный:

type TNotify.Event = procedure (Sender: TObject; Ev: TEvent) of object;

И теперь мы можем работать с событием, как со свойством, например:

OnResize:=MyResizeHandler;

а если мы не хотим ничего делать на событии Resize, то можно написать:

OnResize:=nil;

Спецификатор published относится как раз к свойствам и означает его публикуемость. В Delphi есть целая иерархия типов, например для объекта ListView:

TWinControl

...

TCustomListView

TListView

<здесь следует описать назначение published и ключевого слова final, запись стала невыносимо быстройи неразборчивой>

final

class T{

final int f();

}

final int i=0;

Лекция 23

Множественное наследование.

Множественное наследование до сих пор вызывает споры. Наиболее строгие апологеты объектно-ориентированного подхода считают, что множественное наследование – несколько искусственная форма, и что от нее нужно отказаться. Поклонники языка Smalltalk считают, что если чего-то нет в Smalltalk, то это не имеет никакого отношения к объектно-ориентированному (в Smalltalk нет множественного наследования). Наиболее максимальные языки, такие как CLOS (Command Lisp Object System) и С++, используют множественное наследование, хотя именно критика множественного наследования в С++ и послужила катализатором мнений по этому поводу. Сейчас ситуация с множественным наследованием прояснилась окончательно, и тот вариант множественного наследования, который реализован в языке Java в настоящий момент признан оптимальным.

Такие языки, как Delphi, Оберон, Smaltalk множественного наследования не поддерживают.

П
ри множественном наследовании появляется возможность моделировать более сложные отношения между классами, которые в математике называются решетками. Можно создавать структуры разных типов.

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

class X {

int i;

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

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

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

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