Лекции, страница 5

2019-05-11СтудИзба

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

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

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

Текст 5 страницы из документа "Лекции"

На самом деле здесь традиционные языки программирования дальше всего отходят от указанных концепций. В чем это проявляется?

Например, у нас есть два типа данных: integer и real. С точки зрения именной эквивалентности - это два различных типа. Но в то же время, мы естественным образом можем выполнять следующие операции:

integer:=real;

integer+real;

и др.

То есть в большинстве языков программирования есть правила неявного преобразования типов. И люди, вобщем-то до сих пор спорят - стоит ли допускать неявное преобразование. Понятно, что кое-какие преобразования допускать хотелось бы - в некоторых случаях это достаточно осмысленная операция.

В таких языках как Pascal, C существует неявное преобразование некоторых типов (не всех).

А вот язык Ada полностью удовлетворяет требованию несовместимости различных типов. Возникает два вопроса: - как это удалось? и хорошо это или плохо? Рассмотрим пример:

type weight is new INTEGER;

length is new INTEGER;

В данном случае weight и length несовместимы между собой. Это новые типы и различные типы с точки зрения Ada. Для их совместного использования (например, перемножения) мы должны использовать явное преобразование:

INTEGER(l)*INTEGER(w);

(l имеет тип length, а w - weight)

В языке Ada мы имеем в чистом виде именную эквивалентность типов.

Если мы захотим ввести такой тип данных, как диапазон:

type T is 0..10;

Тогда возникает вопрос, что из себя представляет тип T? C одной стороны, он вроде бы представлен данными целого типа, а с другой стороны, можем ли мы прибавлять к переменным этого типа, например, единицу? Ведь единичка, как константа, будет иметь тип INTEGER, а T - совсем другого типа. Если у нас есть переменная i типа T, то почему мы должны запрещать операции:

i:=0; i:=i+1; ?

А писать:

i:=T(0) и i:=i+T(1) немного пахнет идиотизмом, и программисты для таких правил - люди достаточно несговорчивые.

Как же выбрались из такой ситуации создатели Ada? Они «засунули» в язык понятие подтипа, типа, выведенного из какого-то родительского типа (это совсем не то, что механизм наследования в ООП). Тогда все операции над родительским типом могут быть произведены и над подтипом. В нашем примере T имеет родительский тип INTEGER, а значит к нему применимы операции сложения, умножения, присваивания и т.п.

Если для REAL и INTEGER у нас не общего родителя, то данные два типа по правилам Ada - несовместимы.

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

Чем дальше язык отступает от данной концепции, тем менее он надежен. И в этом плане ненадежность языков, C и Pascal, связана, как раз с пренебрежением к такому правилу.

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

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

+(real, real)

+(integer,integer)

и т.д.

Получается, что есть сущность (операция +), которая принадлежит разным типам, имеет везде одно и то же имя. Конечно, это, вы скажете, функция, а не данные (но во многих языках функции тоже являются данными и тоже имеют тип). Не является ли это нарушением концепции? Бесусловно, да.

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

Приведем, в качестве примера реальную ситуацию из жизни. Один человек может в различных ситуациях принадлежать различным типам. Например, в базе данных предприятия, он выступает, как работник, у которого есть определенный набор данных (ФИО, образование, опыт работы и т.п.) и набор операций над ним: уволить, повысить, перевести в другой отдел, а в базе данных страхового агенства, он может иметь и немного другие данные (ФИО, группа крови, последний страховой взнос и т.д.) и, вообще говоря, другой набор операций: продление страховки, аннулирование, изменение каких-то параметров, выплата страховки и т.п. Для нас понятно, что речь идет об одном и том же человеке, но в разных контекстах его «тип» различен.

И такие ситуации тоже как-то надо моделировать на компьютерах в языках программирования. Возникает ряд проблем, как при объединении баз данных, так и при изменении полей в одной из них. Это, конечно, решается различными способами, но чем больше язык приспособлен для этого - тем лучше. В частности, в Ada это можно решить используя механизм подтипов. Но подтипы не оказались очень удобными, и это стало одной из основных причин того, что Ada не получил широкого распространения.

На Ada было написано много больших и сложных программ (правда, под давлением правительства США, которое ставило требование ко всем программам, используемым в правительственных нуждах, быть написанными на языке Ada - дабы повысить надежность). Однако, очевидно, что Ada устарел в тот же момент, в который и появился, так как ряд проблем возник как раз из-за основной концепции языка - о непересекаемости типов.

С другой стороны - безтиповые языки также не завоевали крупных позиций. Так как писать систему управления полетами или большую базу данных было бы губительно на подобном языке и вызвало бы массу накладных расходов на тестирование и отладку.

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

Язык Ada был создан в 1983 году и в этом же году вышел первый компилятор C++.

Остановимся немного на полиморфизме. Что это такое? Это возможность давать в соответствие одной сущности несколько профилей (в частности, одному имени функции - различные наборы и типы ее параметров)

Реально полиморфные операции были частью любого языка программирования (за исключением, пожалуй, ассемблера). Но такие классические языки, как C, Pascal, Modula2 позволяли полиморфизм только для определенных простых типов.

Более развитые языки, например Ada, вообще говоря, решают проблему полиморфизма частично, а именно, в эти языки введено понятие перекрытия операций (перегрузки операций). Что из себя предствляет концепция перекрытия? В языках, которые разрешают перекрытие операций (а мы будем рассматривать Ada и C++), допускается, чтобы одному имени соответствовали различные объекты - в C и Pascal в пределах области видимости одному имени соответствует ровно один объект, если у нас на Pascal написано:

var i: integer;

i: real;

то такое объявление вызовет ошибку.

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

Возьмем пример из языка Ada:

function F(x: T1) return T2;

function F(x: T3) return T3;

Понятно, что, когда мы делаем вызов F(A), то у нас есть возможность по типу аргумента A определить, какое тело F() следует использовать. Это называется статическим разрешением перекрытия. Аналогично, можно распознать нужное тело функции по числу параметров.

Разница между C++ и Ada с этой точки зрения заключается в двух моментах:

  1. В C++ есть модель наследования, а поэтому правило отождествления профилей значительно более сложное за счет того, что одному объекту может соответствовать несколько типов.

  2. В Ada есть понятие полного контекста операций, и полный контекст операций для функций включает в себя операцию присваивания. То есть по типу левой части оператора присваивания Ada может определить, какое тело функции следует использовать. Если мы поменяем описания функции F() на следующее:

function F(x: T1) return T2;

function F(x: T1) return T3;

то при использовании:

y=F(A)

компилятор не может выбрать тело функции F() по ее профилю (там стоят одинаковые типы T1), однако, зная полный контекст (типы возвращаемых значений) будет подставлено нужное тело, исходя из типа переменной у (если тип y - T2, то будет выбран первый вариант, если T3, то - второй).

В C++ такой номер не пройдет, так как стиль языка позволяет просто писать в строке:

F(A);

и каким образом выбирать тело - неизвестно, поэтому в C++ есть только один механизм определения нужного тела функции - по профилю (по типам и количеству аргументов).

Вобщем, оба языка разрешают статический полиморфизм операций (когда полиморфизм может быть разрешен до начала выполнения программы).

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

Возникает вопрос - является ли достаточным такое решение проблемы полиморфизма путем перекрытия? Вообще говоря, нет. Почему? Приведем классический пример (который всегда приводят, когда хотят показать достоинства объектно ориентированного программирования). Представим себе некоторую графическую среду, например, графический редактор. Он оперирует рядом объектов: окружность, линия, точка, прямоугольник и т.д. Как можно написать процедуру отрисовки всех объектов (предположим, что рисунок у нас состоит из окружности, отрезка и прямоугольника):


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

if тип(х)=circle then drawcircle

else if тип(х)=point then drawpoint

else if тип(х)=rectangle then drawrect

...

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

Мы видим, что основная проблема - это, как связать Draw с конкретным объектом, причем для каждого объекта должна выполняться своя процедура Draw. В классических языках: С, Pascal, Ada - это связывание происходит статически методом, описанным выше (т.е. полиморфизм м.б. только статическим).

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

Языки с концпецией наследования и полиморфизма позволяют из типа данных Figure выводить тип Circle, Point, Line, Rectangle и т.д. И связывать с каждым таким типом свою реализацию метода Draw. В результате, если у нас есть объект X одного из типов, унаследованных от Figure (Circle, Point, Line, Rectangle и т.д.), то для того, чтобы его перерисовать (например, на новом месте), достаточно написать:

X.Draw;

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

Мы видим, что здесь нарушена концепция типов, а именно, объект X принадлежит типу Figure и одному из его производных. А процедура Draw является полиморфной, так как под одним именем скрываются тела для различных типов данных. Такие функции обычно называют виртуальными.

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

На этом мы закончим общую тему о типах данных и перейдем к следующему вопросу.

Глава III. Базисные типы данных

3.1 Простые типы данных

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

Начнем с указателей и ссылок. Указатель - это адрес, его значениями являются адреса конкретных объектов. Указатели обычно типизированные (есть специальный нетипизированный - void* в C++ и аналогичные в других языках - любой указатель можно преобразовать в void*, обратно - нельзя), они содержат в себе адрес на объект определенного типа.Что такое ссылка? Это с точки зрения реализации тоже адреса. Чем же отличаются указатели и ссылки? Если вспомнить, что тип данных характеризуется «набором операций + множество значений», то, исходя из этой формулы, можно сказать, что ссылки от указателей отличаются операциями, которые можно над ними совершать (т.к. множество значений у них одно и то же - адреса).

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