Лекция 18 (1160816), страница 2

Файл №1160816 Лекция 18 (лекции (2002)) 2 страницаЛекция 18 (1160816) страница 22019-09-19СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

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


2)Цепное распределение


С точки зрения копирования, не важно какое распределение памяти применяется. Но с точки зрения эффективности реализации линейное представление эффективнее цепного. Большинство ЯП: линейное распределение памяти, с некоторыми исключениями: SmallTalk- цепное.

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

Его нет в SmallTalk, поэтому его нет и во многих других ЯП. Настоящее множественное наследование есть только в языке С++.

Общий случай наследования в языке С++:

class X: список баз { ... };

Где в элемент списка баз:

[модификатор] имя_типа

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

Что означает множественное наследование?

class X: public Y; public Z { ...};

Это простое и очевидное расширение понятия единичного наследования: Так будет выглядеть структура класса Х(часть, относящаяся к классу Y; часть, относящаяся к классу Z; и часть, относящаяся к классу Х):

Y


Z


X


Если в языке есть только единичное наследование, то структура будет выглядет как дерево:


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

Y



void f() {i = 0;}

void g() {k = 1;}

О каком i и о каком k идёт речь (из Y или Z)? Тут может возникнуть конфликт имён. Так как язык С++ единственный язык реализующий множественное наследование по данным, то как в нём решаются эти проблемы?

С точки зрения функций класса W нет никакого правила, которое говорит, что лучше, и надо явно указать из какого класса это к нам пришло:

Y::i; X::i; Y::k; Z::k;

- есть механизм уточнения имён, с помощью него разрешаем конфликт имён. Но он не будет работать в следующем случае:


В этом случае механизм уточнения имён никак не работает и, поэтому, это случай запрещён. Нельзя, чтобы в списке баз появлялись одинаковые классы (на разных уровнях могут).

Виртуальное наследование

Одиночное наследование позволяет моделировать иерархию. А такое наследование позволяет нам моделировать некоторые сети, но не все сети можно смоделировать с помощью такого механизма. Например, бриллиантовое (ромбовидное) наследование:



Разница с точки зрения распределения памяти. В первом случае у нас есть только один экземпляр объекта класса Х, а во втором- два. Так же очевидно, что при схеме 1) распределение памяти для Z нелинейное.

А зачем нам такое может понадобиться. Например, потоки ввода-вывода из стандартной библиотеки STL:

Это классический случай ромбовидного наследования, и он реализуется следующим образом:

class W: virtual public Y; virtual public Z {}

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

Множественно наследование в ограниченном виде поддерживается в ЯП С# и Java. Там есть специальное языковое понятие «interface»- класс без данных: есть только функции члены и статические члены константы (он содержит только описание функций). Допускается наследование одного класса и множественное наследование нескольких интерфейсов.

Java:

public class X extends Y implements I1,I2,I3 { ... }

/* implements = реализует */

C#:

public class X: список имён { ... };

- список имён ::= одно имя класса + имена интерфейсов. Это расширение концепции единичного наследования.

В С++ можно моделировать произвольные схемы наследования. С матиматической точки зрения там у нас есть некая математическая абстракция «решетка классов».

Во всех остальных ЯП данные можно наследовать только единичным образом.

Наследование и области действия

Во всех ЯП, за исключением Оберона классы рассматриваются как вложенные области действия, то есть каждый новый класс- это новая область действия.

X int i;

Y double i;

Аналогично:

{ int i;

{ double i; - статически вложенный блок

i // double

}

i // int

}

Это статические области действия. Но из вложенного блока нельзя сослаться на i внешнего блока. А в классах можно, используя возможность уточнения: Y -> X::i;. Классы образуют вложенные области действия.

В Аде есть управление видимости, а в языке С++ мы говорм об управлении доступом. В чём отличие?

class X {

...

private:

void f()

...

};

Y f();

В классе Y видимость есть, а доступа нет (для функции f();).


Если бы речь шла об управлении видимостью, то всё было бы «ОК». А тут логически (здравый смысл)- это обращение к функции f(); из класса Z, но компилятору обе функции из X и Z видимы независимо от модификаторв (private, public). Тут компилятор не знает о какой функции идёт речь. Нет ошибки, только если напишем Z::f();. То же самое распространяется и на замещение имён.

Замещение имён


Компилятор сообщит об ощибке, так как он сначала пытается разрешить имя, а потом смотрит доступ, не доступ или что ещё, то есть компилятор начинает разбираться с семантикой только после разрешения имени. Общая схема: сначала компилятор должен догадаться, что это за имя, а потом- правомерно или нет обращение к нему. Тут верно только a = X::g();.

В Обероне закрыть имя запрещено: даже производные классы рассматриваются как единая область действия имён..

А зачем нужно наследование? Его легко промоделировать, что и делается при ОО программировании, в языках, где нет наследования (XTool- надстройка над Xlib: она более ОО, чем какая-нибудь библиотека классов MFC, хотя написана на С}.

struct X { ... };

struct Y {

struct X x;

...

};

-это менее удобно, так как обращаемся через имя переменной «х». То есть чисто одно понятие наследования с точки зрения программирования ничего не даёт. Но, когда есть наследование, появляется концепция динамического связывания.

Глава 2: динамическое связывание

(методов)

С++:

class X {

public:

void f();

...

};

class Y: public X {

public:

void f(); /* у них разные области действия -> нет противоречия */

...

};

X x;

Y y;

x.f(); // X::f();

y.f(); // Y::f();

Аналогично, когда у нас указатели:

X* px;

Y* py;

px->f(); // X::f();

py->f(); // Y::f();

Тут вложенные области действия. Это статическое связывание. Оно может быть разрешено во время компиляции.

Другая ситуация, если у нас опять появляется ключевое слово virtual только в другом смысле (Страуструб в 86 году боялся вводить новые ключевые слова):

class X {

virtual void f();

};

Если перед «f» появилось ключевое слово virtual- это означает то, что это функция будет вызываться в зависимости от динамического типа. Для ООЯП появляется ещё понятие «динамического типа». Как мы уже говорили: «каждый объект данных обладает некоторым типом». В традиционных ЯП этот тип только один, а в ООЯП объект данных может обладать, вообще говоря, совокупностью, но, разумеется, конечной совокупностью типов. Тут если объект данных принадлежит типу Т, то он принадлежит и всем типам из которых наследует Т, тоже относиться и к операциям. Как только объект данным появился в памяти, он своего типа не меняет (так сделано в большинстве ЯП). Тот тип, о котором мы говорили раньше, это так называемый «статический тип»- тип, который приписан объекту в момент его объявления, он должен быть единственным. Коль скоро объект размещён в памяти, то он принадлежит одному статическому типу и этот тип не может меняться. Примеры статических типов:

X x; // статический тип X

Y y; // статический тип Y

Динамический тип: им обладают не все ТД, а именно, указатели и ссылки (у классов его нет):

X* px;

Y* py;

Статический тип px- Х, py- Y, но при присваивании, мы уже начинаем различать статический и динамический типы. Допустимо (так как объектам производных типов можно присваивать объекты базового типа):

px = py;

-теперь px указывает на объектт класса Y. Статический тип px остаётся X. В С указатели должны ссылаться только на объекты соответсвующего типа, следовательно, там нет разницы между динамическим и статическим типом. Как ттолько появилось наследование, то у нас получается, что px может указывать не только на объекты класса Х, но и на объекты любого производного класса. Вот это и есть динамический тип указателя, то есть динамический тип указателя- это тип объекта, на который в данным момент ссылается указатель. Очевидно, он динамический, поскольку при присваивании этот тип может меняться. Тоже самое обобщается и на ссылки, поскольку с точки зрения реализации- это тоже самое.

X &c = x;

c: статический тип- Х

динамический тип- Х

Х &с = y;

c: статический тип- Х

динамический тип- Y

Чем отличаются виртуальные функции от невиртуальных? Строго говоря, сами функции- ничем. Отличаются механизмы их вызова, механизмы их связывания. То есть виртуальные функции с точки зрения реализации и то как они компилируются ничем не отличаются от обычных, невиртуальных функций. Если вызываем функции по объектам:

X x;

Y y;

... <что бы здесь ни было написано>

x.f(); // X::f

y.f(); // Y::f

- то виртуальные и невиртуальные функции неотличимы. А в случае указателей ситуация совершенно другая (для них вызов функции «f» произойдёт в зависимости от динамического типа:

X* px;

Y* py;

...

px->f();

py->f();

то всё зависит (вызов какой функции будет произведён) от того, что написано тут (какие значения имеют px и py).

1)Если тут

px = new X;

py = new Y;

, то динамический и статический типы не отличаються, и будут вызваны:

X::f

Y::f

2)Если тут

py = new Y;

px = py;

, то будет вызвана функция в зависимости от динамического типа:

Y::f

Y::f

3)Если тут

class Z: public Y {

void f() { ... }

...

};

px = new Y;

py = new Z;

, то

Y::f , так как динамический тип px- это Y

Z::f , так как динамический тип py- это Z

Следовательно вызов виртуальной функции происходит в зависимости от динамического типа. Тут речь идёт именно о механизме вызывов. И это (виртуальные функции) применимо только для ссылок и указателей. А почему бы и не сделать, чтобы при «x = y;» динамически менялся тип х? Это можно сделать, но тут придётся динамически перераспределять память.

Delphi, C#, Java: имя объекта- это ссылка, следовательно, нет разницы, вызываем мы через имя объекта или как-то ещё- у нас речь идёт всегда о вызове через ссылку (в Java вообще нет понятия указателя). Любая видная функция рассматривается как виртуальная. Единственное отличие Delphi от C# и Java состоит в том, что в Delphi есть деление функций на виртуальные и невиртуальные. В C# и Java все функции считаются виртуальными (то есть динамически связываемыми).

С++ отличается от Delphi. Если на каком-то уровне иерархии определили функцию как virtual, то все её наследники тоже являются virtual, автоматически (и в наследниках можно явно не указывать). А в Delphi допускается, чтобы функция была невиртуальной.

Механизм виртуального замещения отличается от механизма перегрузки операций: во-первых виртуальные функции должны иметь один и тот же прототип (а в старом варианте С++ даже один и тот же тип возвращаемого значения, а в новом стандарте оно может быть производным типом от типа которым обладает самый первый прототип). Это уже не перекрытие операций (которое как раз и основано на различие прототипов, где компилятор разрешает какой вызов производить), а замещение:

overridding - динамическое замещение

overloading - статическое перекрытие

Delphi:

T = class

procedure P: virtual;

end;

T1 = class (T)

procedure P; override - виртуальная, как в С++

end;

Она не является виртуальной, а подменяет собой виртуальную функцию, если нет override, и, более того, тоже будет если мы просто напишем у неё ключевое слово virtual.

Тоже самое и в языке С#:

public class X {

public virtual void f() { ... };

public void f(int i) { ... };

};

отличаются по прототипам

public class Y: X {

public override void f();

};

И если в классе Y просто напишем void f, то никакого замещения производиться не будет.

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

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

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

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