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

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

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

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

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

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

Int top;

void Push(int x) {..}

int Pop() {..}

};

Классический пример с доступом: пусть у нас есть какая-то переменная, например, в том же самом стеке в некоторых случаях бывает интересно узнать размер стека. Переменная top. Её значение как раз и даёт нам количество элементов в стеке (например, указывает на индекс первого свободного элемента в массиве). Значение top можно открыть top только для чтения, так как любое изменение её значения приводит к разрушению целостности структуры данных. Альтернативная и более хорошая ситуация- сделать, например, функцию “int GetSize();”, которая и возвращает размер. Вданном случае она венёт top и всё хорошо:

Class Stack {

Int body[50];

Int top;

void Push(int x) {..}

int Pop() {..}

int GetSize() {return top;}

};

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

В Обероне-2 можно заводит обычные переменные:

X* INTEGER;

И переменные, доступные только на чтение:

X*- INTEGER;

И нам не надо писать специальную функцию, но это, понятно, частно решение.

Подход Страуструба: в С++ введено понятие inline-функции (возможность вставки функций была и в другхЯП). Это функция (так называемая “встраиваемая”), вместо которой компилятор подставляет её тело, следовательно, никаких операций перехода не будет.

inline int Stack::GetSize() {return top;}

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

Страустуб: для упрощения процесса, если функция-член описана внутри класса, то она inline. В некоторых случаях компилятор будет игнорировать это правило (например, если внутри есть циклы, то они всё-равно ломают конвеер команд).

Тут была поддержка разделения O,P и U (это была аксиома старых ЯП). В современных ЯП, таких как С# или Java дела обстоят несколько иначе: в определении необходимо указывать реализацию (сразу за прототипом метода). Только для абстрактные методов и классов (перед ними должно стоять ключевое слово abstract) мы можем не указывать реализации. Это связано с тем, что соответствующий интерфейс класса должен генерироваться средой программирования с помощью утилит типа javadoc, с помощью интегрированной среды и так далее. То есть один из основополагающих принцыпов современных ЯП- это то, что О и Р сливаются воедино.

Ещё одна интересная особенность языков с классовой структурой, а именно, то, что какие-то странные у нас получаются функции. Если бы мы писали методы Push и Pop на языке Ада или Модула-2 у нас бы появлялся один параметр, как правило первый, это, собственно тип данных стеки и которым мы имеем дело. Ада:

Type Stack is record

body: array (1..50) of integer;

top: integer := 1; //можем сразу инициализировать

End;

Procedure Push(s: inout Stack; x: integer);

Procedure Pop(s: inout Stack; x: out integer);

Pop на Аде нельзя описать в виде функции, так как у функции должны быть параметры только in, а тут первый параметр всегда стек, состояние которого при этом меняется (а то, что компилятор будет, как всегда передовать это в виде ссылки- это уже его проблемы), а у функции на языке Ада все параметры должны быть типа in все зависимости от способа передачи. Можно написать процедуру типа Pick, которая просто считывает первое значение, и её уже можно переделать в функцию. Но самое главное- это то, что первый параметр- это всегда переменная типа стек. В том же стиле мы бы написали стеки на языке Модула-2 и на языке Оберон, поскольку там есть модуль и модуль, как раз, соединяет вместе определение типа стек и соответствующие процедуры.

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

Class X {

void f() {…}

};

Любой функции-члену этого класса неявно передаётся параметр (указатель на объект этого класса):

X* this;

Откуда он берётся? Если, на языке Ада мы будем писать:

Uses Stacks;

s Stack;

Push(s,5); Pop(s,x);

Мы явным образом указываем объект этого класса

На языке C++ и иже с ними, мы бы написали так:

Stack S;

S.Push(…); x = S.Pop();

То есть функции мы вызываем всегда через вид имя_объекта.имя_функции-члена. И адрес этого объекта и передаётся в качестве этого неявного параметра. При этом, опять же, при написании функции-члена (int GetSize();) мы пишем просто return top;, а можно было написать return this->top, но писать это не нужно, посколько не только имена функций, но и имена любых членов (данные или функции) локализуются внутри самого класса и внутри тел функций-членов этого класса мы можем обращаться к этим именам непосредственно. Все имена членов класса непосредственно видимы внутри функций-членов этого класса и потенциально видимы извне этого класса. Внутри функций-членов мы можем писать Push и Pop без всякой квалификации, а извне мы обязаны уточнять через имя объекта. В результате функции получаются значительно более компактными. С другой стороны хорошо это или плохо. Вообще говоря, подобного рода нотация (классовая нотация) удобна с точки зрения программиста, но это вопрос вкуса. Но далее мы увидим, что так как в ООЯП есть понятие динамического связывания методов класса, то все языки основанные на такой парадигме класса, они, как раз, используют привязку только к одному объекту, и динамический вызов метода- это как раз вызов метода в зависимости от типа объекта, который стоит в левой части. (апример, “s.Draw”). Все рассматриваемые нами ООЯП используют динамическое связывание метода только по одному объекту. Страуструб обсуждал возможность мультиметодов, возможность динамического выбора по нескольким объектам, например, когда мы определяем операцию “+” для типов Т1 и Т2. Так вот, если мы хотим динамически привязать операцию “+”, то мы должны её привязать, соответственно, либо к типу Т1, либо к типу Т2. А вот динамический выбор на основе Т1 и Т2- это новая особенность и на С++ её смоделировать практически невозможно или, по крайней мере, очень тяжело. Как ариант- необходимо синтаксически расширять базис языка. А вот в Аде’95, где изначально (в Аде) не было привязки к отдельному объекту. Мы вполне можем перечислить здесь несколько объектов. Мы увидим, что в объектном расширении языка Ада (Ада’95 – это новый ЯП, снизу-вверх полностью совместимый с Адой’83), там как раз мульти методы достались нам практически за бесплатно.

То есть однозначно говорить какая схема лучше или хуже- нельзя, скорее всего это просто дело вкуса, но, тем не менее, как мы видим, современные ЯП так или иначе ориентируются на схему, которую ввёл Страуструб в языке С++, и которая, на самом деле, была скопирована с языка Симула’67, то есть члены-функции, члены-данные и привязка к одному объекту.

Другие ЯП. Общий синтаксис очень похож: ключевое слово class, далее имя соответствующего типа класса и далее мы описываем соответствующие члены, причём синтаксис, поскольку так или иначе он ориентирован на С++ (C# и Java), всё очень похоже. С той только разницей, как уже было подчёркнуто, О и Р слито в одно понятие класса. Есть, конечно, небольшая разница, даже чисто синтаксическая, например, и в С# и в Jave у нас не может речь идти о том, что this являетмся указателем на соответствующий класс, хотя естественно этот неявный параметр есть, но он является ссылкой (адрес) на объект этого класса. И функциям будет передоваться, соответственно “X this;”:

Class X {

Void f(); - ей передаётся X this;

};

В Delphi ситуация таже самая только синтаксис немножка другой:

Type Stack =

Class

Body: array [0..50] of integer;

Top: integer;

Procedure Push(x: integer);

Function Pop(): integer;

End;

В Delphi принцып разделения О, Р и U проведён полностью и мы вообще не имеем право писать реализацию функций Push и Pop внутри самого класса. Мы обязаны писать это только в разделе implementation [Delphi опирается на Турбо Паскаль, который сам опирался на объектный Паскаль- не тот, которым называют Delphi, а старый объектный Паскаль (70-е годы)]:

Procedure Stack.Push(x: integer);

… -self передаётся по умолчанию

Begin

End;

Похоже на запись на языке С++, но немножко другие правила квалификации, немножко другой синтаксис использования. Процедурам и функциям – членам класса на языке Delphi передаётся параметр self, который является ссылкой на объекты соответствующего класса, поскольку Delphi тоже ссылочный язык (все классы имеют ссылочную семантику). Это же слово применяется и в Java (эта терминалогия идёт от SmallTalk’a), так как оно более естественно, а Страуструп не стал вводить его (а ввёл this), так как программисты часто в ранних программах использовали это слово как идентификатор, а он хотел совместимости снизу-вверх языка С++ с языком Си (по крайней мере с объявлениями). Например, по тем же причинам, возбуждение исключения не raise (Delphi, Ada), a throw (оно позже перешло и в Java и в C#), так как оно уже было занято стандартном вызывом из библиотеки сигналов в системе Unix. А this программисты если и использовалииспользовали, то в основном в качестве идентификаторов переменных, а это не так страшно, как идентификатор типа или функции, так как переменные можно переименовать. This перешёл в С#. Но с точки зрения семантики смысл один и тот же. Более того, с точки зрения реализации первый компилятор С++ (а именно Си фран) был разработан именно как компилятор с языка С++ на стандартный Си. И все эти функции транслировались как обычные глобальные функции, которым приписано какое-то уникальное имя и в качестве первого параметра как раз указатель на объект этого класса.

Специфичность определения типов с помощью

классов от обычного определения типов

1)Функции-члены класса (которым неявно передаётся параметр this) привязывается к имени объекта и работают через это имя объекта:

S.Pop();

2)В чистых (они изначально проектировались как ОО языки, без всяких отсылок к старым ЯП, без требований совместимости) ООЯП, таких как С# и Java: в них программа- это последовательность определений классов (если забыть про раздельную трансляцию). А в Delphi и C++ смешенение различных парадигм программирования (классическая модульная структура и классовая структура и многие другие механизмы, которые остались от старых парадигм). В языке Java вообще отсутствует понятие глобальных переменных и глобальных функций. В C# кроме этого могут быть структуры и перечислимый тип.Следовательно, не существует глобальных переменных и глобальных функций. И поэтому в этих языках значительно шире, чем в языке С++ используется понятие статических членов классов- они не имеют привязки к самому объекту- похожи на глобальные переменные или функции, но только имя соответсвующей переменной или функции связано областью видимости с соответствующим классом.

Smalltalk: переменная класса- это статический член класса. А нестатические члены- это переменные экземпляра.

В С++ и других языках, основанных на нём, понятие переменной класса/экземпляра обобщено на произвольный объект, в том числе процедуры и функции. Пример:

class X {

static int x;

int y;

};

С точки зрения компилятора структура этого класса выглядит так: объект класса Х состоит из единственного поля:


int y

А откуда берётся х? х размещается один раз в памяти для всех экземпляров этого класса вне зависимости от существования элементов этого класса. Это как бы глобальная переменная х. Но в отличие от глобальной переменной она доступна только по общим правилам функций-членов:

X a;

a.x - нельзя на С# (можно на С++)

Альтернатива:

X::x - предпочтительнее (в Java или C# такая форма записи- единственная)

Java, C#: X.x – указываем явно, через имя класса, чтобы обратиться к этому элементу. Статическая переменная- это глобальная переменная, локализованная внутри класса. Тут класс начинает работать как просто некоторый модуль. Статическая функция- аналогично. Она соответствует глобальной функции, имя которой локализовано внутри класса. Им никакой указатель/ссылка на объект не передаётся (this, self). А обращение к ней через имя класса.

А с чего начинает работу программа в Java или С#? В Си/С++ у нас есть глобальная функция main(). Тут в одном из классов должна существовать статическая функция main с прототипом:

public class X {

public static int main(string [] args);

};

Имя программы совпадает с именем этого класса. Тут мы передаём в main просто аргументы командной строки, а количество элементов не надо передавать, так как у массива в C# и в Javе есть его свойство- длина (динамический атрибут любого массива). Без понятие статических функций не смогли бы написать main, так как теперь она существует вне зависимости от того, есть объекты класса Х или нет. В Java и C# статические члены классов используются значительно чаще, чем в С++.

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

Или, например, ТД, элементы которого нельзя ничтожать, а отводить можно только в динамической памяти (В С# и Java все объекты классов заводятся только в динамической памяти, и мы их явно не уничтожаем, их уничтожает только сборщик мусора, а вот на Паскале такой ТД написать нельзя [к которому неприменима процедура uncheck deallocation]):

Class X {

Private:

X();

~X();

Public:

Static X* Make() {return new X;}

};

X* p = X::Make(); - единственный способ создать объект

X a; - ошибка, так как конструктор умолчания

(функция, которая всегда работает при

инициализации объекта класса) приватный и

объявление вне класса Х

delete p; - нельзя, так как деструктор (функция, которая

вызывается при разрушении объекта класса)

тоже приватный

А в процедуре Make можем делать new X, так как это функция-член класса Х и она имеет доступ ко всем членам этого класса.

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