Лекция 06 (лекции (2002)), страница 2

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

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

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

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

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

а


В Delphi синтаксис немножко другой – там речь идет о вызове конструктора. То есть если мы описываем объект Х типа Т

X:T;

то опять же размещается только ссылка на объект типа Т, в начале неинициализированная, а инициализировать ее мы с помощью явного вызова конструктора

X:= T.Create;

Это языки с так называемой ссылочной семантикой. И как следствие необходимо всегда помнить, что в этих языках, например, если у нас есть Х1, Х2 типа Т

X1,X2:T;

или соответственно в таких языках как C# или Java

Т Х1,Х2;

То присваивание

Х1=Х2

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

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

int i;

Есть ссылочный объект х.

int &x;

- такое объявление у нас не допустимо. Мы должны обязательно, если речь идет о переменной типа ссылка, проинициализировать

int &x= i;

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

x=3;

эквивалентны тому, что вместо х употребляется i. Разумеется подобного рода стиль программирования мягко говоря нехорош, хотя допустим в С++.

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

int f(int);

int f(int&);

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

f(i);

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

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

int f(ref int);

которое просто говорит о том, что соответствующий параметр передается по ссылке, и не нужно раздувать базис языка, не нужно добавлять новый тип данных. Спрашивается, почему Строуструп пошел по другому пути? Он, все таки, добавил новый тип данных в базис языка. Обратите внимание, что за исключением типа данных bool, который появился только в 90-ые годы, ссылочный тип данных - это единственное расширение базиса языка. С точки зрения базиса и С, и С++ совпадают с одним единственным исключением, а именно с ссылочным типом данных. Где еще нужен ссылочный тип данных? Вспомним, что уже на ранних стадиях развития языка С++ Стоуструп проводил идею перекрытия операций. Идея, как видите, плодотворная, поскольку во всех современных языках программирования идея перекрытия имен процедур и функций реализована. Она оказалась очень удобной. Единственное исключение – это язык Оберон, поскольку в принципе вещь удобная, но теоретически без нее обойтись можно. Перекрытие операций – вещь полезная, но кроме этого Строуструп реализовал перекрытие и стандартных знаков операций. При этом из всех языков, которые позволяют такое перекрытие, С++ обладает наиболее богатым объемом операций. Т. е., как уже говорилось, нельзя перекрывать только операции доступа к элементам . , операцию разрешения области видимости :: , связанную с этим операция доступа к указателю на член класса .*, ну и нельзя еще перекрывать трехместную операцию ?: ,причем, как написал Строуструп: "только по причинам, что я не придумал ни одного нормального контекста, в котором это перекрытие могло бы оказаться полезным", а так, почему бы и эту не перекрыть. Все остальные операции, включая и операцию вызова функции ( ) , и операцию разименования указателя -> и многие другие операции можно перекрывать, в том числе и операцию индексирования [ ]. Спрашивается, а как можно перекрыть операцию индексирования, чтобы она была функционально эквивалентна обычной операции индексирования в том же самом языке, как С.Если у нас есть массив

int a[10];

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

a[0];

Cпрашивается, какой тип данных возвращает а[0]?

Если a[0] возвращает просто int, то мы можем писать

int i = a[0];

но мы можем писать и

a[0] = i;

Здесь это уже не просто значение целого типа данных, мы не можем суда подставить значение целого типа данных – в левой части оператора присваивания должно содержатся нечто, что имеет адрес. Указатель, разименнованный указатель – ради бога, поскольку *р слева мы можем писать потому, что она имеет адрес, константу не можем писать, поскольку константа адреса не имеет. То есть a[0] должно обозначать нечто, что дает адрес. Но с другой стороны, адрес у нас есть – это указатель, но указатель нужно еще разименовывать. И без введения типа данных ссылка нельзя было перекрыть ряд операций, поскольку операция индексирования возвращает именно ссылку на объект, и используя эту ссылку мы можем, например, модифицировать содержание этого объекта, брать из него значение, все, что угодно. Все, что можно делать с объектом, мы можем делать и с ссылкой. И все так называемые операции над ссылкой, за исключением операции инициализации это и есть операции с объектами на которые ссылается данная ссылка. И следовательно, введение ссылочного типа данных – это не просто каприз, а расширение базисной системы типов на всего один только тип ссылка позволило действительно сделать язык достаточно мощным. Без ссылок перекрытие ряда стандартных операций просто никакого бы смысла не имело. С этой точки зрения, конечно, ссылки в языки С++ несколько особый класс, который немножко отличен от понятия ссылки в таких языках, как С#, Delphi, Java.

У нас остался еще один тип данных, а именно – функциональный тип данных. Значениями функционального типа данных служат процедуры и функции. Такой тип данных есть например в расширении Паскаль, Турбо Паскаль, например, и как следствие в языке Delphi, Функциональный тип данных появился в языке Модула 2, в частности для того, чтобы можно было передавать процедуры и функции как параметр потому, что, вспомним – в стандартном Паскале у нас в дополнение к двум обычным способам передачи параметров, а именно – по значению и по ссылке с помощью ключевого слова var, добавились еще 2 специальных способа параметра, а именно – параметр-процедура и параметр-функция. Вот в Турбо Паскале уже параметров процедур и функций просто нет потому, что там появился функциональный тип данных. То же самое произошло и с языком Модула 2 и, как следствие, с Обероном. Там появились соответствующие функциональные типы данных. Например, если хотеть написать некоторый тип

type Prc = procedure(var integer);

Prc – процедура, у которой есть один формальный параметр. Это синтаксис Модула 2, в Турбо Паскале и в Delphi здесь необходимо указывать переменную, но в общем смысл один и тот же. И вот теперь у нас есть тип данных, мы можем описывать как переменные, так и формальные параметры типа Рrc. Что может являться значениями такого функционального типа данных? Имена других процедур и функций, которые описаны в программе. Каким образом реализуется такой функциональный тип данных? Заметьте, что и в С и в С++ можно описать это логически. Это будет нечто такого вида

typedef void (*f(int &));

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

VAR X: Prc;

Присвоить Х какую-то процедуру Proc

X:= Proc;

где Proc – это процедура, которая имеет такой прототип и описана у нас в программе. Ну и понятно, что с точки зрения реализации теперь это просто адрес процедуры. Мы теперь можем писать

Х(i);

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

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

Как с точки зрения надежности пытаются решить проблему функциональных типов данных дизайнеры языков программирования? Возьмем язык Ада. Язык Ада, вообще говоря, всегда очень аккуратно поступает с указателями. Спрашивается: что он будет делать с указателем на функцию? Тут ситуация следующая: в языке Ада 83 все было очень просто, а именно функционального типа данных там вообще не было. А как же тогда написать процедуру вычисления интеграла? Очевидно, в этой процедуре в качестве одного из параметров должна передаваться подынтегральная функция, а писать для каждого интеграла особую процедуру, которая будет вызывать эту функцию, вообще говоря, достаточно не удобно. Но создатели языка Ада решили эту проблему следующим образом. Как уже было сказано, основное назначение процедурных типов данных – это либо передача параметров процедур и функций, либо моделирование понятия callback. И то и другое оказалось возможным именно за счет ограниченности функционального типа данных. Значения его ограничены заранее известным, то есть статическим набором процедур и функций. Те процедуры и функции, которые описаны в вашей программе – это и может быть допустимое значение функционального типа (с нужным прототипом). Следовательно, все возможные значения статически известны, и следовательно, связывание формальных и фактических параметров можно провести не на стадии выполнения, передавая адреса соответствующих процедур и функций, а на стадии трансляции. В Аде есть так называемое понятие родовых сегментов (generic segment). Они несколько похожи на шаблоны языка С++. Как шаблоны языка С++, так и родовые сегменты Ада – это есть статически параметризованные конструкции. В отличие от процедур и функций, которые параметризовывать можно только объектами данных, родовые сегменты можно параметризовать именами типов, именами процедур и функций и т.д.. Когда мы будем разбирать статическую параметризацию – это отдельная глава в языках Ада и С++ (в других языках, которые мы рассматриваем статической параметризации просто нет) мы увидим, каким образом можно написать, например, ту же самую процедуру интеграл, но сделать ее не динамически настраиваемой, а статически настраиваемой. И в принципе, с точки зрения гибкости использования это никак на эффективность использования языка не влияет. То же самое можно сделать и с концепцией callback, т. е. некоторой процедурой - обработчиком внешних событий. В языке Ада 83 есть понятие задачи, а именно параллельного процесса. Так вот задачный тип данных как раз не опасен потому, что он служит абстракцией понятия процесса, а процесс это все-таки не указатель, это другая сущность. А подпрограммный тип данных был не нужен. Интересно то, что в Аде 95, в которой было много расширений языка, в частности мы обсуждали расширение понятия указателей, подпрограммный тип данных появился. Спрашивается: что же изменилось? Как и с концепцией указателя язык изменился за счет того, что изменились требования к языку, изменилась программная среда вокруг. В Аде 95 подпрограммные типы данных понадобились из тех же соображений, почему понадобились указатели на нединамические объекты – потому, что необходимо было обеспечивать интерфейсы с другими ЯП. И если интерфейс с языком С, то там без понятия указателя не обойтись, и как следствие появилась новая концепция – расширение концепции указателей. Но кроме этого, обойтись без передачи функций как параметров в языке С не возможно и, следовательно появился подпрограммный тип данных. При этом, если бы речь шла о программировании на одном и только одном языке, можно было бы обойтись без этого типа данных. А в случае, когда нужно обеспечивать интерфейсы с другими ЯП, подпрограммный тип данных оказался просто необходим. Но тем не менее, проблема с ненадежность функционального типа данных все равно остается. Решают ее в разных языках по-разному. В языке Delphi эта проблема никак не решена потому, что Delphi обеспечивает совместимость с Турбо Паскаль, и там все старые средства Турбо Паскаль, в том числе функциональный тип данных, остались. Язык Java также решил эту проблему очень просто – функциональный тип данных в языке Java отсутствует. Спрашивается: а как же тогда можно передавать процедуры и функции в качестве параметров? А не нужно передавать процедуры и функции как параметры. Java отличается от языка Ада 83 тем, что там есть очень мощное понятие класса. Класс интегрирует в себе и данные и операции. Поэтому, например, одно из решений этой проблемы это, вообще говоря, если нам нужна функция, мы завертываем ее в особый класс. Те, кто занимался изучением стандартной библиотеки шаблонов в языке С++ STL, вспомнят специальные, так называемые функции-классы, которые есть в стандартной библиотеки шаблонов. Это некоторый класс, в котором переопределяется операция вызова функции ( ). Основным назначением такого класса – держать эту функцию. Из этогокласса не с помощью механизма вывода, а с помощью статической параметризации, для эффективности, мы переопределяем соответствующим образом, настраиваем эту операцию вызова, а все алгоритмы, которые работают с этим классом, знают, что он реализует функцию, которую можно достать по имени объекта класса, применяя к нему эту перекрытую операцию ( ). То же самое предлагается сделать на языке Java, а именно: мы определяем некоторый класс. В языке Java, правда, статической параметризации нет, но зато там есть динамическое связывание методов. И вот мы определяем некоторый класс. У него, соответственно, определяем некоторую функцию f. И в результате, если нам нужно, скажем, написать процедуру интеграл, то соответственно мы говорим, что вместо функции мы вызываем некоторый класс с, и в качестве подынтегральной функции у него будет f. И в результате, если нам надо написать процедуру интегрирования, для какой-то подынтегральной функции ff. Мы выводим новый экземпляр класса с и в нем переопределяем функцию f так, чтобы она вызывала или делала тоже самое, что и функция ff. В результате проблема с передачей функций как параметров решена с помощью ведения такого понятия как класс-функция. Это не языковое понятие, это понятие методов программирования. Когда мы будем рассматривать подробнее концепцию производных класса, в частности в языке Java, мы увидим, что в Java появились даже специальные конструкции - анонимные классы, которые как раз упрощают программирование такого рода классов, чтобы не придумывать дополнительные имена.

Что же сделано в C# с этой точки зрения? Традиционный процедурный тип данных там реализовывать не стали, из-за проблем, связанных с ненадежностью понятия процедурного типа данных. Там естественно можно использовать метод языка Java, но разработчики C# пошли несколько по другому пути – они ввели понятие делегата. Сейчас мы не будем обсуждать понятие делегата в языке C# - мы вернемся к нему позднее, когда будем рассматривать концепцию класса и наследования. Сейчас просто отметим, что понятие делегата, с одной стороны, выглядит как тип данных, а с другой стороны, его значениями могут являться только функции. При этом объекты этого типа данных мы также должны с помощью соответствующей операции new, указывая конкретную функцию, которая будет служить в качестве значения этого делегата. При этом приятная особенность делегата, например, по сравнению с данными обычных функциональных типов – то, что, на самом деле, делегат – это не один указатель на какую-то функцию, а его можно рассматривать как совокупность указателей. Т. е. у нас есть понятие callback – какого-то обработчика внешних событий и, если при традиционном стиле программирования у нас это единственный указатель на одну функцию, который вызывается в случае возникновения какого-то внешнего события, то с делегатом даже проще: делегат – это совокупность обработчиков. Т.е. можно на одно и тоже событие повесить несколько обработчиков – так называемое broadcast , т.е. широковещательная обработка события и, в результате вызова делегата по очереди вызываются все функции, которые были добавлены в соответствующий делегат. В частности, например в языке C# есть отдельный тип данных событие, который представляет из себя частный случай делегата. И эти события, вообще говоря, интегрированы в систему языка. Когда мы будем говорить об объектно-ориентированном программировании, мы вернемся к понятию делегатов и к понятию событий в языке C#. На этом давайте закончим обсуждение простых типов данных.

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