Лекция 14 (Лекции (2009) (Саша Федорова))

2019-09-19СтудИзба

Описание файла

Файл "Лекция 14" внутри архива находится в папке "Лекции (2009) (Саша Федорова)". Документ из архива "Лекции (2009) (Саша Федорова)", который расположен в категории "". Всё это находится в предмете "языки программирования" из 7 семестр, которые можно найти в файловом архиве МГУ им. Ломоносова. Не смотря на прямую связь этого архива с МГУ им. Ломоносова, его также можно найти и в других разделах. .

Онлайн просмотр документа "Лекция 14"

Текст из документа "Лекция 14"

11


Лекция 14

Абстрактные классы и интерфейсы

Любой класс - это тип данных. Однако абстрактный класс – это не абстрактный тип данных!

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

Абстрактный класс возникает, когда в нескольких классах существуют признаки, общие для всех объектов. Именно эти общие признаки мы выносим в базовый класс, как можно дальше «наверх».

Однако некоторые функциональности могут быть реализованы только в производных классах. Таким образом неизбежно возникает понятие абстрактного класса.

Все языки, включающие понятие динамически свзяанного метода, включают понятие абстактного класса. Исключение: Оберон-2.

(Turbo Pascal 5.5– тоже не было понятия абстрактного класса, но там существовала стандартная процедура Abstract(). В Delphi абстрактный класс появился.) Большинство языкв для обозначения абстрактного класса используют ключевое слово abstract.

C#, Java

Абстрактный класс – это обычный класс со свойствами, признаками и методами, некоторая функциональность которого нам не известна.

Любого объект обладает поведением и состояние. Поведение объекта выражео его методами, а состояние – членами-данными.

Существуют методы и члены-данные, общие для всех – они принадлежат базовому классу, но реализовать некоторые из них мы можем только в конкретном(не астрактном) классе. Мы абстрагируемся от некоторого конкретного поведения.

Пример

Класс Figure. Чем он обладает:

1) точка привязки – есть у любой фигуры

2) все фигуры можно нарисовать, но каждую – по-разному(пример абстрактного поведения, разного для всех)

3)можем двигать фигуру – в принципе, обще для всех фигур. Любая фигура движется, по сути, одинаково(если мы имеем в виду параллельный перенос)

Можно ли реализовать алгоритм рисования для абстрактной фигуры?

Нет! Если фигура, к примеру, точка – это вызов функции рисования одного пикселя. Отрезок же рисуется совсем по-другому.

Move(dx, dy); //достаточно реализовать, например, в базовом классе

{ x+=dx; y+= dy; }

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

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

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

В C# и Java, если перед методом стоит ключевое слово abstract 

1) реализация данного метода не требуется

2) класс становится абстрактным

3) перед определением класса должен стоять спецификатор abstract.

Замечание

Абстрактный класс и абсрактный тип даных – это ортогональные понятия.

abstract class Base{
abstract public void Draw();

….

};

Класс называется абстактным  в нем есть хотя бы один виртуальный метод.

C#

class D: base{
public override void draw(){……};

};

Java

class D: extends base{
public override void draw(){……};

};

//обязательно поставить тело Draw!

Страуструп отказаслся от ключевого слова abstract, и использовал понятие чисто виртуальной функции

virtual прототип =0;

Может как содержать реализацию, так и не содержать.Существует даже контекст, где чисто виртуальная функция будет вызвана – но это приведет к ошибке.

Замечание.

При вызове функции в конструкторе ее виртуальность снимается(тут она не имеет смысла, ведь в конструкторе мы создаем объект).

Пусть у нас есть иерархия X->Y->Z

Класс X: пусть в нем есть функция f

virtual X() { f(); //this->f, через указатель, но компилятор подставит X::f() }

Пусть в классе Y f замещается.

Как мы знаем, конструкторы класов вызываются в порядке иерархии. При вызове функции в конструкторе класса Х функция f замещаться не будет!

На любой вызов нереализованной виртуальной функции вызовется стандартная процедура Abstract, которая повалит всю нашу программу.

Итог: в любом конексте выов чисто виртуальной функции ведет к ошибке, поэтому в большинстве языков создание объекта абстрактного класса запрещено.

Ада 1995, 2005

Если процедура привязана к тегированому типу данных, ее можно сделать абстрактной. При попытке ее вызвать опять же будет выдана ошибка. В Ада есть абстрактные методы, а абстрактных классов нет. Можно считать, что абстрактный класс в Ада – это тегированная запись с хотя бы одним абстрактным методом.

Примеры

Яркий пример неизбежности абстрактного класса – класс-архиватор. Существуют признаки, общие для всех: имя файала, куда он архивируется(либо какой-то поток в памяти, куда упрятываются архивированные данные).

Методы: extract, add, delete.

Все меоды, связанные с форматом архивации – виртуальные. Ведь мы хотим поддерживать разные форматы, а потому имеет смысл переорпределять методы для каждого конкретног формата в соответствющем классе-потомке.

Еще один пример – класс Image, метод FromFile – реализуется по-разному для каждого конкретного формата изображения.

Интерфейсы

Существует ли связь между абстрактным классом и интерфейсом?

Формально это два ортогональных понятия.

В абстрактном классе мы абстрагируемся от реализации методов.

В интерфейсе мы абстрагируемся от всей структуры класса.

Так как и там и там речь идет об абстракции, существуют ситуацииЮ когда абстактный класс превращается в абстрактный тип данных: если все методы скрыты, а открыты только виртуальные методы.

Пример. Множество.

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

Очевидно, что в любом множестве должны поддерживаться операции include(const T&) и exclude(const T&).

Предлагается сделать так:

class ISet{

virtual void exclude(const T &)=0;

virtual void include(const T &)=0;

………………………………………..

};

Классы подобного рода принято называть интерфейсами.

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

Такой класс называется абстрактным типом данных, если его структура полностью инкапсулирована(настолько, что ее вовсе нет). 

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

Существует некий метод, который не хочется делать абстрактным. Это деструктор. Если мы не объявим деструктор как виртуальный, то это в 99% случаев будет свидетельствовать об ошибке.

Base * px = new Derived();

px->f();

delete px; //если мы не объявим деструктор как виртуальный, то уничтожится не объект класса Derived, а объект класса Base. Ресурсы освобождены не будут. Эту ошибку будет найти очень сложно, как и любую ошибку, связанную с утечкой ресурсов.

Общее правило: если есть классы с виртуальным методом, делайте деструктор виртуальным.

Итак, пишем:

class ISet{

virtual void exclude(const T &)=0;

virtual void include(const T &)=0;

virtual ~ISet(){};//ПУСТОЙ

};

По умолчанию, если не написать virtual, деструктор создасться невиртуальным.

Чисто виртуальным деструктор быть не может(тогда он вызовется в деструкторе подобъекта и будет ошибка)

Пример.

сlass SList{…………}; //базовый

class SList_set: public ISet, private SList{

{

ISet* Make() { …………..return new SList_set(); }

};

Заметим, что SList наследуется приватно – тот редкий сллучай, когда нужно приватное наследование.

Таким образом, что в С++ нет языкового понятия интерфейса, однако он легко моделируется вышесказанным образом.

В C# и Java понятие интерфейса существует на языковом уровне.

Interface имя {

объявление членов

};

Кроме функций-методов, как мы помним, в C# может появляться еще и свойство.

interface ISample{

int pi; //поле рассматриваетс как статическая константа

Если написать

int pi{gte; set}

то оно превратится в свойство.

Кстати, перед определением свойство может стоять слово virtual. То есть свойства могут быть виртуальными или чисто виртуальными.

В Java вместо get и set есть getpair и setpair.

Методы в интерфейсах объъявляются без модификаторов – все, что внутри интерфейса, обязано быть публичным по умолчанию. Однако protected все-таки может стоять. Модификатор private ставить бесмысенно.

Часто понятие интерфейса заменяют на контракт.

Класс, реализующий интерфейс, остается абстрактным, если не реализует ВСЕ методы.

Интерфейс на С++ можно смоделировать, как мы показали в примере на ээтой странице, при помощи множественного наследования. А множественное наследование всегда можно смоделировать при помощи включения объектов одного класа в другой как членов-данных.

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

Заметим: в чистом виде множественное наследование есть только в С++, а C# и Java множественное наследование реализовано только для интерфейсов.

C#

class D: имя, интерфейсы:

Java

Class D extends Base implements именя интерфейсов

Интерфейсы могут содержать внутри себя любые вложенные классы.

Пример(Java)

Interface ISample{

сlass Settings{…} ; //может быть конретным классом

Settings InitData = new Settings();

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

Замечание. Первая проблема при множественном наследовании – это конфликт имен. Пусть у нас есть колода карт(ну, не колода конечно, а класс):

interface ICard{

void Draw(); //раздавать колоду

interface IUIControl{

Draw();

}

Пусть наши программные средства умет работать с IUIControl.

Class Sangle implements ICard, IUIControl{//возникает конфликт имен: два имени Draw. Что из них мы должн релизовывать? Выбрать либо первый, либо второй класс.

В С++ такие реализации разрешаются через явное обращение. Вот так:

class D: public I1, I2{

virtual void I1::f(){…………};

virtual void I2::f(){…………};

………………

};

В С# появляется так называемая явная и неявная реализация интерфейсов.

Неявная реализация – это то, что мы всегда называем обычной реализацией.

Пример неявной реализации интерфейсов:

interface ISample{

void f(); };

class CoClass: ISample{

public void f(){………………..}; //если тут не поставить public, компилятор заругается.

};

Явная реализация интерфейсов:

class CoClass2: ISample{

void ISample f() {…………….}

//тут спецификатор public отсутствует, потому что попытка написать тут public карается

};

Как же вызвать данный метод, если он не публичный?

D * px;

px->f(); //непонятно, какой метд я хочу вызывать – ошибка.

Но px->I1::f(); //снова ошибка: попытка вызова чисто виртуальной функции.

Мы же хотим вызвать заместителя для I1. Это длается так:

((I1*)px)->f();

Замечание. Слова «явный» и «неявный» должны относиться к приведению типов, а не к классам(интерфейсам).

CoClass2 x;

(ISample)x.f();//явное приведение

При явной реализации вызов возможен лишь ри явом приведении.

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