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

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

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

px->g( ) // ошибка, так как в X функция g даже не определена.

Ведь в случае когда вызывается функция от класса Y, ей должен быть передан указатель класса py:

X

px, pz

Y

py

Z

а у нас реально указатель другой – на начало.

В случае же

pz->g( )

какая функция будет вызвана? Очевидно, Y::g( ), в качестве указателя this ей будет передан pz (на начало вышеприведенной таблицы). Что же получается? А именно то, что в случае множественного наследования в ТВМ должно быть еще смещение. Фактически, мы должны иметь два варианта ТВМ. Если вызываются виртуальные методы от X (в нашем случае это f( ) ), то смещение равно нулю, если же вызываются методы для второго класса (а также третьего, четвертого и т.д.), то нужно добавлять некий сдвиг внутри таблицы, он равен –(размер X).

Z

X

ссылка на ТВМ XZ

X

Y

ссылка на ТВМ YZ

Y

Z

TВМ XZ:

Z::f

Z::i

ТВМ YZ:

Y::g

Z::f

Z::i

Заметим, что ТВМ Z получается «спрятанным» в совместных ТВМ с другими классами.

Таким образом, для кажого класса, от которого происходит наследование, мы должны иметь совместную ТВМ этого класса и Z (потомка). Разумеется, это не есть хорошо.

Smalltalk

В SmallTalk не линейное, а цепное представление класса:



Начинается все со ссылки на объект базового класса. Плюс каждый объект имеет ссылку на таблицу методов (ТМ), можно не писать слово «виртуальных», так как в SmallTalk все методы виртуальны. Более того, SmallTalk настолько динамический язык, что там можно динамически изменять ТМ – среди методов класса (аналог статических методов в C++) есть методы, которые позволяют добавлять или убирать методы из ТМ данного класса. Получается, что можно динамически менять поведение объекта. В C++ это невозможно.

В SmallTalk в принципе нельзя во время компиляции определить – применим ли данный метод для данного объекта, поэтому вызов метода осуществляется следующим образом: пусть у нас вызывается некий метод MSG, он ищется в ближайшей к нему ТМ, если он там есть, то вызывается, если нет – происходит поиск в следующей ТМ по иерархии вверх (если метод не будет найден, возникнет сообщение об ошибке). Следует отметить, что вызов MSG может оказаться некорректным, если есть несоответствие в параметрах (ведь ТМ может изменяться динамически, и компилятор это несоответсвие отловить просто не может), в этом случае возникнет сообщение об ошибке, но уже во время выполнения.


Понятно, почему в SmallTalk нет множественного наследования. И так накладные расходы велики (хотя бы динамический поиск – это не подставление смещения в C++). Если же мы добавим множественное наследование, то поиск метода будет осуществляться не по линейному списку, а по дереву, что на порядок сложнее и дольше:

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

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

Снятие механизма виртуального вызова

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

class X {

virtual void f( );

...

};

class Y public X {

void h( ) { f ( ); ...} // нельзя сказать, из какого класса

//будет вызван метод

// f( ), он может быть вызван из X, Y или какого-то

// наследного класса Z в зависимости от динамического типа

...

};

Если мы знаем, какой метод какого класса хотим получить, то можно снять вызов виртуального метода, написав вместо f ( ), например, X::f(), таким образом мы дадим точно понять, какую реально функцию хотим, и компилятор подставит сюда вызов f( ), как невиртуальной функции. То есть виртуальность и невиртуальность – это механизм вызова, а не самой функции, ибо сама функция реализуется одинаково в обоих случаях.

Заметим, что снять механизм виртуального вызова извне класса невозможно.

Абстрактные методы. Абстрактные классы.

Когда мы начинали обсуждать пример связанный с графическими примитивами:

class Shape {

int x,y;

virtual void Draw(bool);

void Move(...);

...

};

Класс Shape – вершина иерархии. Заметим, что в методе Move у нас вызывается Draw. Это напрямую означает, что мы должны написать реализацию Draw, иначе компилятор выдаст ошибку. Но смысла в этой реализации нет никакого, так как она сведется в результате к вызову пустого метода, да и назначение Shape не предусматривает смысла в реализации Draw.

Классы аналоги Shape, из которых потом выводятся другие классы, призваны для определения интерфейсов виртуальных методов.

Из этих соображений были введены абстрактные классы и абстрактные виртуальные методы (не путать с абстрактными типами данных).

class X {

virtural void f( )=0;

};

“=0” и означает то, что f( ) – абстрактный виртуальный метод. Страуструп дико боялся введения новых ключевых слов по вполне понятным причинам, хотя объявление могло бы выглядеть и, например, так:

abstract virtual void f( );

Что такое абстрактный виртуальный метод? Это метод, который указывает на то, что в любом классе, унаследованном от данного функция f( ) должна быть переопределена. Но она не должна быть определена здесь. Классы, в которых есть абстрактные методы называют абстрактными классами. Они отличаются от обычных тем, что объекты данных классов нельзя заводить в программе. Если в классе X есть хотя бы один абстрактный метод, то при попытке создать экземпляр данного класса компилятор выдаст ошибку.

Очевидно, что метод Draw() должен быть абстрактным.

Если мы не переопределим в классе-наследнике абстрактный метод, то порожденный таким образом класс будет также абстрактным. Заметим, что в стандартных библиотеках очень часто можно встретить целые слои абстрактных классов. Это допустимо.

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

Возникает вопрос, связаны ли между собой абстрактные классы (АК) и абстрактные типы данных (АТД)? На первый взгляд нет. Но представим себе такую вещь. Пусть есть класс, в котором данные отсутствуют вообще, а все методы объявлены, как виртуальные и абстрактные:

class Abstract {

public:

virtual void f()=0;

virtual void g()=0;

};

Раньше имело смысл заводить класс без данных в случае, если все функции в нем статические. Здесь речь идет о функциях-членах и в классе нет никаких данных. Утверждается, что это в самом чистом виде абстрактный тип данных. Реализация данного типа данных – выведение неабстрактного типа данных. Приведем стандартный пример, пример множества:

class Set {

public:

virtual void Include (Set & S)=0;

virtual void Include (Elem & S)=0;

virtual void Exclude (Elem &S)=0;

...

};

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

class Slist {...}; // операции работы с линейным списком

class ListSet: public Set, public Slist {

...// благодаря множественному наследованию переопределяются

//мы наследуем и интерфейс и реализацию.

// следует, конечно, переписать все операции Set через операции

// SList

};

Теперь всем клиентским модулям, использующим Set, можно подставлять класс ListSet, и они будут прекрасно работать. Но клиентские функции ничего не знают реализации. Отсюда следует еще и минимизация перекомпиляции – ведь реализацию класса ListSet мы можем поместить куда угодно.

Информация о классе Set представляет из себя указатель на ТВМ.

Здесь мы получаем наиболее гибкое отделение реализации от определения.

Интересно, что объекты ListSet будут представлять из себя одну ссылку на ТВМ и набор данных:

ссылка на ТВМ

DATA

причем не произойдет никаких «размножений» ТВМ, так как один из классов-предков имел ТВМ, а другой только данные. Мы даже можем написать универсальный контейнер, который с помощью линейного списка реализует множество, стек, очередь Q – где все они будут являться АК.

Поскольку данные наследуются только по одному пути (или вообще не наследуются, а указываются в наследнике), то мы лишаемся всех тех проблем, которые были связаны с наследованием данных из разных источников, они решены в C++, но как-то неестественно.

Java

В Java наследование только единичное:

class Y extends X {

...

};

Но еще в Java введен тип данных – interface, строго говоря, это совокупность типов данных.

interface имя { описание членов интерфейса};

Член интерфейса – это либо описание метода (без тела), либо константы (static final int i=0).

В Java есть понятие чисто виртуальной функции (вспомним, что в Java все функции виртуальны). У таких функций нет реализации. Интерфейс – это интерфейс, он сам по себе ничего реализовывать не должен. Но тем не менее реализован он все-таки должен быть. Поэтому общая форма наследования в Java выглядит так (следует заметить, что в Java все классы являются потомками класса Object, поэтому, если опустить “extends X” в нижеследующем примере, то Y будет непосредственным потомком Object):

class Y extends X implements <список_интерфейсов> { ...}

Если класс реализует все функции из списка интерфейсов, то это – неабстрактный класс. Если не все – абстрактный (чтобы из него можно было вывести что-то еще).

Также как и в C++ в Java нельзя создавать экземпляры АК. Но ссылки и указатели задавать можем.

Очень много понятий реализуется через интерфейсы. Например, проблема копирования. В C++ эта проблема решена через перекрытие операции присваивания и конструктора копирования. В Java же вместо этого делается так: есть

объект Object

и

interface Cloneable;

Object может реализовывать Cloneable, чтобы сделать свой объект клонируемым следует переопределить методы из Cloneable, поскольку

Object implements Cloneable.

Таким же образом можно запретить копирование или реализовать его нестандартно (стандартно – это побитово).

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

Лекция 25

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

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

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

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