Текущая версия |
Ваш текст |
Строка 1: |
Строка 1: |
- | ''С++''<br>
| + | == From Ebaums Inc to MurkLoar. == |
- | ''Ада''<br>
| + | We at EbaumsWorld consider you as disgrace of human race. |
- | ''С#'' c 2004<br>
| + | Your faggotry level exceeded any imaginable levels, and therefore we have to inform you that your pitiful resourse should be annihilated. |
- | ''Java'' c 2005<br>
| + | Dig yourself a grave - you will need it. |
- | | + | |
- | Все современные языки, использующиеся в промышленности, поддерживают идею статической параметризации.
| + | |
- | Продолжаем рассматривать идею родовых модулей в ''Аде''.
| + | |
- | === п.1. Родовые модули языки ''Ада'' === | + | |
- | | + | |
- | ''Ада-83'' – принцип РОРИ пронизывает весь этот язык. Получился очень мощный и одновременно эффективный механизм. Порождение нового пакета порождало новый экземпляр данного типа.
| + | |
- | | + | |
- | package Stack – два параметра – тип элемента размер стека:
| + | |
- | | + | |
- | <pre>
| + | |
- | generic
| + | |
- | type T is private;
| + | |
- | size: integer;
| + | |
- | package Stack is
| + | |
- | Push
| + | |
- | Pop
| + | |
- | end Stack;
| + | |
- | </pre>
| + | |
- | | + | |
- | Можно ли так запрограммировать процедуры, чтобы они эффективно работали для любого размера стека? Конечно, да!
| + | |
- | | + | |
- | Конкретизация:
| + | |
- | | + | |
- | <pre>
| + | |
- | package IStack is new Stack(integer, 128);
| + | |
- | </pre>
| + | |
- | | + | |
- | Тривиальная реализация – простая макроподстановка integer и 128. Плюс – крайняя простота. Минус – очень сильное разбухание кода – сколько объявлений, столько и различных процедур. ''Ада-83'' требовала отдельной компиляции спецификации и реализации.
| + | |
- |
| + | |
- | Теперь представим себе другую ситуацию, например пусть у нас есть родовая процедура сортировки:
| + | |
- | | + | |
- | <pre>
| + | |
- | generic
| + | |
- | type ElType is private;
| + | |
- | type Index is range <>;
| + | |
- | type Arr is array (Index) of ElType;
| + | |
- | with function <(x, y : T) return Boolean (<>);
| + | |
- | procedure G_SORT(A: in out Arr; L,R : Index);
| + | |
- | </pre>
| + | |
- | | + | |
- | Как написать спецификацию той же шаблонной функции на ''С++'', считая, что уже имеется Vector <T>? Вот так:
| + | |
- | | + | |
- | <pre>
| + | |
- | template <class T, class Index>
| + | |
- | void Sort(Vector <T>&V, Index L,R);
| + | |
- | </pre>
| + | |
- | | + | |
- | В процедуре Sort обязательно встретится нечто вроде:
| + | |
- | | + | |
- | <pre>
| + | |
- | if (v[i]<v[j])
| + | |
- | </pre>
| + | |
- | | + | |
- | Только во время конкретизации происходит процесс выведения типа и компилятор узнает, есть ли вообще у v операция индексирования или нет. До этого производится только синтаксическая проверка.
| + | |
- | | + | |
- | В ''Аде'' большое разнообразие типов формальных параметров родового модуля.
| + | |
- | Формальные параметры родовых модулей:
| + | |
- | | + | |
- | параметр-переменная <=> любое константное выражение<br>
| + | |
- | type T is private <=> любой тип с операцией присваивания<br>
| + | |
- | type T is range <=> любой дискретный тип с упорядоченностью и функциями «следующий» и «предыдущий»<br>
| + | |
- | type T is delta <=> любое плавающее выражение<br>
| + | |
- | < > <=> при конкретизации процедуры мы можем не указывать этот вариант (параметр по умолчанию).<br>
| + | |
- | | + | |
- | Пусть у нас есть:
| + | |
- | | + | |
- | <pre>
| + | |
- | procedure StrSort is new G_SORT(String, Integer, TARR);
| + | |
- | </pre>
| + | |
- | | + | |
- | C помощью < > компилятор находит функцию < для строк и подставляет как параметр по умолчанию.
| + | |
- | Родовые сегменты – абсолютно необходимая в ''Аде'' конструкция, потому что там нет передачи процедур и функций по параметру. Как по-другому реализовать функцию, скажем, вычисляющую интеграл? Мы должны передавать вещественный тип-параметр и саму подынтегральную функцию. Допустим, мы вводим новый вид чисел, например комплексный, то есть запись. Мы должны описать тип чисел как приватный и передавать как сравнение, так и всю арифметику. Хотя много всего, но зато будет одна процедура и для вещественных, и для комплексных чисел, и для кватернионов.
| + | |
- | Компилятор должен видеть не только спецификацию данной абстракции, но и тело. Гибкость повышается, но тело родовой абстракции должно быть доступно в любой момент конкретизации. За в этой жизни надо платить! Либо мы повышаем гибкость, либо производительность. В ''Аде-83'' механизм родовых модулей – единственный, который поддерживал ОО. Как вы думаете, что самое главное, что появилось в ''Аде-95''? Правильно, класс – тегированная запись:
| + | |
- | | + | |
- | <pre>
| + | |
- | type T is tagged
| + | |
- | </pre>
| + | |
- | | + | |
- | Какова была основная цель введения дженериков в ''C#'' и ''Java''? Для коллекций. Если мы почитаем определение языка ''C#'', то первый шаблон, который мы найдём, это реализация стека:
| + | |
- | | + | |
- | <pre>
| + | |
- | Elem Stack {}
| + | |
- | </pre>
| + | |
- | | + | |
- | Раньше же мы видели Object []body;
| + | |
- | Дальше приведение типа, и если мы пропускаем проверку, получим ошибку времени выполнения. В основном коллекции являются не гетерогенными, и, используя шаблоны, можно сильно увеличить производительность. Самый мощный механизм – шаблоны в ''С++''. Почему же они более мощны и гораздо более сложны, чем в других языках?
| + | |
- | | + | |
- | Шаблоны в ''С++'': <br>
| + | |
- | 1) Функции<br>
| + | |
- | 2) Классы<br>
| + | |
- | <br>
| + | |
- | а) Параметр-класс <=> Любой тип<br>
| + | |
- | б) Параметр-переменная <=> Константное выражение<br>
| + | |
- | | + | |
- | <pre>
| + | |
- | template <class T, int size> class Stack {...}
| + | |
- | </pre>
| + | |
- | | + | |
- | T – тип данных, size может быть везде, где фигурирует целая константа. Конкретизация происходит явным образом.
| + | |
- | Stack <int, 256> может появляться везде, где может появляться имя типа.
| + | |
- | После Stack <int, 256>, увидев Stack <int, 2*128>, компилятор ничего не сгенерирует, т.к. уже один раз сгенерировал.
| + | |
- | А вот Stack <int, 64> порождает новый класс, хотя в общем-то Push и Pop в этом случае делают одно и то же, что и в случае Stack <int, 256>. Но компилятор мужественно породит новый кусок кода…
| + | |
- | | + | |
- | Stack <int, 64> S;
| + | |
- | Вот здесь начинается генерация кода. Но в ''С++'' у нас раздельная трансляция.
| + | |
- | Шаблоны – очень мощная вещь, но неграмотное их использование неопытным программистом ведет к разбуханию кода…
| + | |
- | Если одинаковые шаблоны сгенерированы в разных модулях, некоторые компиляторы борются с этим, используя PCH, хотя это делает трансляцию зависимой.
| + | |
- | | + | |
- | Для функций то же самое, но конкретизация не обязательна. Рассмотрим:
| + | |
- | | + | |
- | <pre>
| + | |
- | template <class T> void Sort (Vector <T>&V);
| + | |
- | </pre>
| + | |
- | | + | |
- | Sort порождает бесконечное семейство конкретных реализаций.
| + | |
- | | + | |
- | Представим, что у нас в программе есть:
| + | |
- | | + | |
- | <pre>
| + | |
- | Vector <string> X;
| + | |
- | Sort(X);
| + | |
- | </pre>
| + | |
- | | + | |
- | В Sort должен явно встречаться код:
| + | |
- | | + | |
- | <pre>
| + | |
- | if (v[i]<v[j])
| + | |
- | </pre>
| + | |
- | | + | |
- | Компилятор опять же ничего проверить не может. Эта проверка происходит только в момент конкретизации. В ''Аде-95'' и ''С++'' ситуация одинаковая и не такая, как в ''Аде-83''. В момент конкретизации компилятору надо дать полную информацию обо всём шаблоне, и ни о каком принципе РОРИ речи идти не может.
| + | |
- | Этим ''С++'' не ограничивается. Пока что было очень похоже на ''Аду-95''. Какой недостаток?
| + | |
- | | + | |
- | В первых версиях шаблонов в ''С++'' было невозможно:
| + | |
- | | + | |
- | <pre>
| + | |
- | template <class T>
| + | |
- | T f() {…}
| + | |
- | </pre>
| + | |
- | | + | |
- | В новых версиях можно:
| + | |
- | | + | |
- | <pre>
| + | |
- | Sort <int>(a);
| + | |
- | </pre>
| + | |
- | | + | |
- | Но это не всё. В ''С++'' есть механизм частичной специализации.
| + | |
- | | + | |
- | === п.2. Шаблоны в ''С++'' ===
| + | |
- | | + | |
- | <pre>
| + | |
- | Vector <const char *>a;
| + | |
- | Sort(a);
| + | |
- | </pre>
| + | |
- | | + | |
- | Будет подставлена функция < для указателей, и ошибки в программе не будет, но работать она будет неправильно.
| + | |
- | | + | |
- | <pre>
| + | |
- | template <class T> bool less (T& x, T& y) {
| + | |
- | return x<y;
| + | |
- | }
| + | |
- | </pre>
| + | |
- | | + | |
- | Это описание шаблонной функции. Хорошая функция сортировки должна работать через шаблонную функцию сравнения. Но проблема со * остаётся. Что делать? А вот что.
| + | |
- | | + | |
- | Пишем:
| + | |
- | | + | |
- | <pre>
| + | |
- | template <> bool less <const char *> (const char *p1, const char *p2) {
| + | |
- | return strcmp(p1,p2);
| + | |
- | }
| + | |
- | | + | |
- | template <> class Vector <void *>;
| + | |
- | </pre>
| + | |
- | | + | |
- | Подставь вместе T void * и сгенерируй код. (?)
| + | |
- | | + | |
- | Для векторов возможны такие реализации:
| + | |
- | | + | |
- | 1) template <class T> class Vector {…}<br>
| + | |
- | 2) template <> class Vector <T*>;</br>
| + | |
- | | + | |
- | <pre>
| + | |
- | Vector <long > V;
| + | |
- | Vector <int> V1;
| + | |
- | </pre>
| + | |
- | | + | |
- | Оба по первой реализации и разные.
| + | |
- | | + | |
- | <pre>
| + | |
- | Vector <const char *> v2;
| + | |
- | Vector <int *>v3;
| + | |
- | </pre>
| + | |
- | | + | |
- | Оба по второй и одинаковые.
| + | |
- | | + | |
- | Будет также эффективно, как и встроенный в язык вектор.
| + | |
- | Механизм частичной специализации очень эффективен.
| + | |
- | Физики очень не любили использовать язык ''С''. Компиляторы с ''ФОРТРАНА'' были, как ни странно, эффективнее компиляторов с ''С''. ''С''-шные функции требуют слишком много проверок, пример: memcpy (проверяет перекрытие областей памяти и много-много чего прочего).
| + | |
- | С появлением шаблонов ситуация изменилась. Многие математические библиотеки, такие как Boost, Loki – это именно библиотеки шаблонов – очень производительны. Читай у Александреску про его библиотеку шаблонов Loki. У STL много недостатков, но написана она исключительно производительно в смысле эффективности.
| + | |
- | | + | |
- | Вспомним:
| + | |
- | | + | |
- | <pre>
| + | |
- | Find(It first, It last, …)
| + | |
- | </pre>
| + | |
- | | + | |
- | Для каждого конкретного типа можно написать частичную специализацию Find
| + | |
- | *I == X (?)
| + | |
- | | + | |
- | Можно передавать третьим параметром compare, и вызывать но это неэффективно, так как это срывает работу конвейера. Выход – функтор. Перекрываем операцию ( ):
| + | |
- | | + | |
- | <pre>
| + | |
- | сlass Finder {
| + | |
- | public:
| + | |
- | bool operator ()(T&x, …) {
| + | |
- | …
| + | |
- | }
| + | |
- | }
| + | |
- | </pre>
| + | |
- | | + | |
- | === п.3. ''C#'', ''Java'' – обобщенные классы ===
| + | |
- | | + | |
- | У них очень простой синтаксис и похожая идея:
| + | |
- | | + | |
- | <pre>
| + | |
- | class Stack <T> {…}
| + | |
- | interface IComparable <T> {…}
| + | |
- | </pre>
| + | |
- | | + | |
- | Параметризовать можно как классы, так и интерфейсы и методы:
| + | |
- | | + | |
- | <pre>
| + | |
- | public void add <T> (T x) {…}
| + | |
- | </pre>
| + | |
- | | + | |
- | Слово class просто синтаксически не нужно. Компилятор производит первичный синтаксический анализ и перевод в MIL/Байт-код. Конкретизация же происходит при выполнении кода. Код генерируется оптимальным образом.
| + | |
- | | + | |
- | В ''Java'' в качестве параметризованных типов только классы.
| + | |
- | Вместо Stack <int> S надо Stack <Integer> S
| + | |
- | | + | |
- | В ''C#'' на такое пойтить не могли. Там же есть структуры!
| + | |
- | Если аргумент – класс или интерфейс, код разный. Для ссылок одинаковый.
| + | |
- | | + | |
- | В ''Java'':
| + | |
- | if (Stack<Integer>.getClass==Stack<String>.getClass()) даст true
| + | |
- | | + | |
- | В ''C#'':
| + | |
- | | + | |
- | <pre>
| + | |
- | сlass Dictionary <K, V> {
| + | |
- | }
| + | |
- | </pre>
| + | |
- | | + | |
- | K – тип ключа,
| + | |
- | V – тип значения.
| + | |
- | | + | |
- | Явно при реализации должно быть нечто вроде:
| + | |
- | | + | |
- | <pre>
| + | |
- | public void Add( K Key, V Value) {
| + | |
- | …
| + | |
- | if (K<K1) …
| + | |
- | …
| + | |
- | }
| + | |
- | </pre>
| + | |
- | | + | |
- | На это будет выдана ошибка. Потому что функции < может не быть.
| + | |
- | | + | |
- | Надо:
| + | |
- | | + | |
- | <pre>
| + | |
- | if ((IComparable)K<K1)
| + | |
- | </pre>
| + | |
- | | + | |
- | Вместо этого можно:
| + | |
- | | + | |
- | <pre>
| + | |
- | class Dictionary <K, V> where K:Icomparable
| + | |
- | </pre>
| + | |
- | | + | |
- | Можно теперь ошибки не бояться.
| + | |
- | Возвращаемся к старой доброй ''Аде-83''.
| + | |
- | | + | |
- | «Я когда-то за счет изменения нескольких функций выиграл в производительности 30%. Это, извините меня, о-го-го!»
| + | |
- | | + | |
- | Кстати, по поводу ''С++''. В ''С++'', в отличие от ''Ады'', есть механизм подстановки параметров по умолчанию.
| + | |
- | new
| + | |
- | delete
| + | |
- | | + | |
- | В итоге концепция шаблонов пронизывает все современные языки.
| + | |
- | Наиболее мощная концепция в ''С++'', но за счёт сложности можно писать очень неэффективные программы.
| + | |
- | В ''Java'' и ''C#'' достигнут между производительностью и гибкостью.
| + | |
- | На этом закончим лекцию и вместе с ней весь курс.
| + | |
- | | + | |
- | === Схема проведения экзамена по Языкам Программирования: ===
| + | |
- | | + | |
- | 1) Экзамен письменный, длится одну пару
| + | |
- | | + | |
- | 2) Можно пользоваться печатными материалами, если это не типографская продукция
| + | |
- | | + | |
- | 3) Всего восемь задач, максимум за каждую - 6 баллов
| + | |
- | | + | |
- | 4) when баллы>=36 => 5, when 24<=баллы<36 => 4, when 12<=M<25 => 3, default => 2
| + | |
- | | + | |
- | '''Задачи досрочного экзамена (19 декабря):'''
| + | |
- | | + | |
- | '''1-ый вариант.'''
| + | |
- | | + | |
- | 1) В каких из перечисленных ниже языков программирования при обработке
| + | |
- | исключительных ситуаций используется семантика завершения? Объяснить, что она означает.
| + | |
- | | + | |
- | ''Ада'', ''Модула-2'', ''Оберон'', ''Оберон-2'', ''С'', ''С++'', Java, ''C#''
| + | |
- | | + | |
- | 2) Объяснить, что означает оператор foreach языка ''C#''. Какие условия накладываются
| + | |
- | на класс-коллекцию, чтобы он мог использоваться в данном операторе?
| + | |
- | | + | |
- | 3) Объяснить все смыслы ключевого слова final в языке ''Java''.
| + | |
- | | + | |
- | 4) Перечислите способы передачи параметров в языках программирования. Какие из них
| + | |
- | реализованы в языках ''Ада-95'' и ''Оберон''?
| + | |
- | | + | |
- | 5) Что будет выдано в стандартный канал вывода при вызове функции F()?
| + | |
- | | + | |
- | <pre>
| + | |
- | class X {
| + | |
- | public:
| + | |
- | void g() { cout << 1 << ' '; }
| + | |
- | virtual void f() { g(); }
| + | |
- | };
| + | |
- | | + | |
- | class Y: public X {
| + | |
- | public:
| + | |
- | void g() { cout << 2 << ' ';}
| + | |
- | void f() { g(); }
| + | |
- | };
| + | |
- | | + | |
- | class Z: public Y {
| + | |
- | public:
| + | |
- | void g() { cout << 3 << ' '; }
| + | |
- | void f() { g(); }
| + | |
- | };
| + | |
- | | + | |
- | X x; Y y; Z z;
| + | |
- | X *px = &x; Y *py = &y; Z *pz = &z;
| + | |
- | | + | |
- | void out() {
| + | |
- | px->f(); px->g(); py->f(); py-> g();
| + | |
- | cout << '\n';
| + | |
- | }
| + | |
- | | + | |
- | void F() {
| + | |
- | | + | |
- | out(); px = py;
| + | |
- | out(); py = pz;
| + | |
- | out();
| + | |
- | }
| + | |
- | </pre>
| + | |
- | | + | |
- | 6) В каких из перечисленных ниже языков программирования нет перечислимого типа?
| + | |
- | | + | |
- | ''Ада'', ''Паскаль'', ''Модула-2'', ''Оберон'', ''Оберон-2'', ''С'', ''С++'', ''C#''
| + | |
- | | + | |
- | 7) Написать спецификацию родового (generic) класса в языке ''Java'', который будет
| + | |
- | реализовывать очередь. Тела методов писать не нужно.
| + | |
- | | + | |
- | 8) В каких из перечисленных ниже языков есть возможность раздельной трансляции
| + | |
- | вложенных модулей? Привести пример на одном из таких языков.
| + | |
- | | + | |
- | ''Ада'', ''Паскаль'', ''Модула-2'', ''Оберон'', ''Оберон-2'', ''С'', ''С++'', ''Java'', ''C#''
| + | |
- | | + | |
- | {{Языки Программирования}}
| + | |