Редактирование: Сравнение Языков Программирования

Материал из eSyr's wiki.

Перейти к: навигация, поиск

Внимание: Вы не представились системе. Ваш IP-адрес будет записан в историю изменений этой страницы.

ПРЕДУПРЕЖДЕНИЕ: Длина этой страницы составляет 81 килобайт. Страницы, размер которых приближается к 32 КБ или превышает это значение, могут неверно отображаться в некоторых браузерах. Пожалуйста, рассмотрите вариант разбиения страницы на меньшие части.

Правка может быть отменена. Пожалуйста, просмотрите сравнение версий, чтобы убедиться, что это именно те изменения, которые вас интересуют, и нажмите «Записать страницу», чтобы изменения вступили в силу.

Текущая версия Ваш текст
Строка 1: Строка 1:
На этой страничке собираются материалы, которые могут помочь при подготовке к экзамену по языкам программирования.
На этой страничке собираются материалы, которые могут помочь при подготовке к экзамену по языкам программирования.
-
ЯП из курса: C, C++, Java, C#, Pascal, Delphi, Оберон-2, Модула-2, Ада (83 и 95 стандарты).
+
ЯП из курса: C, C++, Java, C#, Pascal, Delphi, Оберон-2, Модула-2, Ада (83 и 95 стандарты)
Полезные ссылки:
Полезные ссылки:
-
* [[w:Сравнение языков программирования|Сравнение ЯП в википедии]]
 
-
* [http://progopedia.ru/ Энциклопедия языков программирования]
 
-
* [http://citforum.ru/programming/cpp/aglav.shtml Книжка Страуструпа]
 
-
* [https://habrahabr.ru/post/161205/ Ликбез по типизации в языках программирования / Хабрахабр]
 
-
План (краткий, взят из методички Головина, подробный см. в самой [[Media:pl.exam.variants.pdf|методичке]]):
+
[http://ru.wikipedia.org/wiki/%D1%F0%E0%E2%ED%E5%ED%E8%E5_%FF%E7%FB%EA%EE%E2_%EF%F0%EE%E3%F0%E0%EC%EC%E8%F0%EE%E2%E0%ED%E8%FF Сравнение ЯП в википедии]
 +
 
 +
[http://progopedia.ru/ Энциклопедия языков программирования]
 +
 
 +
[http://home.perm.ru/strannik/st_txt_prog_02.html/ Немножно рекламное сравнения большинства языков]
 +
 
 +
План (краткий, взят из методички Головина, подробный см. в самой [http://cmcmsu.no-ip.info/download/pl.exam.variants.pdf методичке]):
== Базисные типы данных в языках программирования: простые и составные типы данных, операции над ними ==
== Базисные типы данных в языках программирования: простые и составные типы данных, операции над ними ==
Строка 18: Строка 20:
; Character: Как я понял, существует несколько разновидностей (зависит от размера) и является особым перечислимым типом (Enumeration)
; Character: Как я понял, существует несколько разновидностей (зависит от размера) и является особым перечислимым типом (Enumeration)
; String: Массив '''Character''' фиксированной длины. Так же есть стандартные пакеты, реализующие строки квазистатической и динамической длины.
; String: Массив '''Character''' фиксированной длины. Так же есть стандартные пакеты, реализующие строки квазистатической и динамической длины.
-
; Floating point: Эти типы обычно определяются вручную в виде конструкции, где Num_Digits указывает максимальную погрешность:
+
; Floating point: Эти типы обычно определяются вручную в виде конструкции, где Num_Digits указывает минимальную (минимально допустимую?) погрешность:
'''digits''' Num_Digits
'''digits''' Num_Digits
Строка 40: Строка 42:
'''end'''
'''end'''
-
==== Поподробнее об Access ====
+
=== ОБЕРОН и ОБЕРОН-2: ===
-
Здесь будем пользоваться следующим примером:
+
-
 
+
-
'''type''' Person '''is record'''
+
-
First_Name : String (1..30);
+
-
Last_Name : String (1..20);
+
-
'''end record''';
+
-
+
-
'''type''' Person_Access '''is''' '''access''' Person;
+
-
 
+
-
Так как в Аде указатели могут указывать на объекты только из динамической памяти, тип Access очень тесно связан с кучей (в Аде вместо понятия кучи используется понятие пула). Такая связь позволяет для каждого типа объекта держать свой отдельный пул, который может управляться программистом, например можно вручную изменять размер пула:
+
-
 
+
-
'''for''' Person_Access''''Size''' '''use''' New_Size; ''-- 0 запрещает создание новых объектов в пуле''
+
-
 
+
-
Создадим пару экземпляров нашей структуры:
+
-
Father: Person_Access := '''new''' Person; ''-- неинициализовано''
+
-
Mother: Person_Access := '''new''' Person'(Mothers_First_Name, Mothers_Last_Name); ''-- инициализованно''
+
-
 
+
-
Тип Access - это высокоуровневый указатель, представленный записью с полями. Например, разыменовать указатель можно следующим образом:
+
-
Mother.'''all'''.Last_Name = Father.'''all'''.Last_Name ''-- здесь, Mother.'''all''' имеет тип Person;
+
-
 
+
-
Кроме того типы указателей различаются уровнями доступа (read-only и read-write):
+
-
'''type''' Person_Read_Access '''is''' '''access constant''' Person; ''-- read-only''
+
-
'''type''' Person_RW_Access '''is''' '''access all''' Person; ''-- read-write''
+
-
 
+
-
Кроме оператора '''new''' в пуле переменные можно размещать модификатором '''aliased''' (у таких переменных есть атрибут 'Access):
+
-
Child: aliased Person;
+
-
Child_Access: Person_Access := Child''''Access'''
+
-
 
+
-
Есть еще очень много интересного по этой теме. Все было взято [http://en.wikibooks.org/wiki/Ada_Programming/Types/access тут].
+
-
 
+
-
=== ОБЕРОН и ОБЕРОН-2 ===
+
; Отличия:
; Отличия:
Строка 131: Строка 102:
** Целые числа:
** Целые числа:
*** Знаковые: byte, short, int, long (8-, 16-, 32-, 64-битные).
*** Знаковые: byte, short, int, long (8-, 16-, 32-, 64-битные).
-
*** Беззнаковый 16-битный: char (код символа в UTF-16<ref>Была правка UTF-16 → Unicode. Откатил. Пояснил на странице обсуждения.</ref>).
+
*** Беззнаковый 16-битный: char (код символа в UTF-16).
** Числа с плавающей точкой: float, double (32-, 64-битные; IEEE 754).
** Числа с плавающей точкой: float, double (32-, 64-битные; IEEE 754).
Строка 139: Строка 110:
Также существует специальный тип null.
Также существует специальный тип null.
-
Объектом в Java считается экземпляр класса или массив. Значением ссылочного типа является ссылка на объект (или специальное значение null). Значение переменной ссылочного типа можно изменить, в отличии от C++.
+
Объектом в Java считается экземпляр класса или массив. Значением ссылочного типа является ссылка на объект (или специальное значение null). Все объекты (включая массивы) обладают методами класса Object (java.lang.Object) (иначе говоря, с т.з. Java-программиста все объекты *наследуют* методы класса Object). Строковые литералы (например, "Hello world!") являются объектами типа String (== экземплярами класса String).
-
 
+
-
Все объекты (включая массивы) обладают методами класса Object (java.lang.Object) (иначе говоря, с т. з. Java-программиста все объекты *наследуют* методы класса Object). Строковые литералы (например, "Hello world!") являются объектами типа String (иначе говоря, экземплярами класса String).
+
Операции над простыми типами почти идентичны C/C++, однако могут выбрасывать исключения. Конкатенация строк: "Hello " + "world!" (может принимать в качестве одного из аргументов не только строку, но и любой из целых типов).
Операции над простыми типами почти идентичны C/C++, однако могут выбрасывать исключения. Конкатенация строк: "Hello " + "world!" (может принимать в качестве одного из аргументов не только строку, но и любой из целых типов).
Больше информации о типах, значениях и переменных: http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html .
Больше информации о типах, значениях и переменных: http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html .
- 
-
=== C++ ===
 
- 
-
; Целые типы:
 
-
: char - размер как для хранения символа, определяется машиной (обычно байт)
 
-
: short - размер, соответствующий целой арифметике на данной машине (обычно, слово)
 
-
: int
 
-
: long
 
-
: long long
 
-
Для всех целых типов есть unsigned аналоги. По умолчанию - знаковые (так что, например, signed int - то же самое, что int).
 
-
Исключение - char. Его знаковость/беззнаковость зависит от реализации.
 
-
; С плавающей точкой:
 
-
: float
 
-
: double
 
-
: long double
 
-
1 = sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long)<br>
 
-
sizeof(float) <= sizeof(double) <= sizeof(long double)
 
- 
-
'''const''' <тип> <имя_переменной> = <значение>;
 
-
// Значение переменной не может изменяться после инициализации (инициализация обязательна).
 
- 
-
; Aрифметические операции:
 
-
: + (плюс, унарный и бинарный)
 
-
: - (минус, унарный и бинарный)
 
-
: * (умножение)
 
-
: / (деление)
 
-
: Над целыми - операция % получения остатка: 7%2 = 1
 
-
; Операции сравнения:
 
-
: == (равно)
 
-
: != (не равно)
 
-
: <, >, <=, >=
 
- 
-
Также логические операции ( &&, || ), побитовые операции(&, |, ^, <<, >>), а так же сокращённые формы многих операций: +=, -=, %=, &&=, ||=, &=, ++, -- (последние два имеют префиксные и постфиксные формы) и им подобные.
 
- 
-
При присваивании и арифметических операциях C++ выполняет все осмысленные преобразования между основными типами, чтобы их можно было сочетать без ограничений.
 
- 
-
; Производные типы:
 
-
: * - указатель на
 
-
: *const - константный указатель на
 
-
: & - ссылка на
 
-
: [] - вектор (одномерный массив), индексация с 0
 
-
: () - функция, возвращающая
 
-
: Унарное & - операция взятия адреса
 
- 
-
Например:<br>
 
-
char* p // указатель на символ<br>
 
-
char *const q // константный указатель на символ<br>
 
-
char v[10] // вектор из 10 символов<br>
 
-
char c; p = &c; // p указывает на c
 
=== C# ===
=== C# ===
-
; Встроенные типы:
+
; Встроенные типы
: 1. sbyte, byte - 8-битное целое число
: 1. sbyte, byte - 8-битное целое число
: 2. short, ushort - 16-битное целое число
: 2. short, ushort - 16-битное целое число
Строка 214: Строка 134:
;Структуры и классы
;Структуры и классы
В C# структуры являются урезанной версией класса. Память под структуры наравне с простыми типами выделяется на стеке (если, конечно, они не являются частью объекта — память под объекты всегда выделяется на куче). Ограничения на структуры:
В C# структуры являются урезанной версией класса. Память под структуры наравне с простыми типами выделяется на стеке (если, конечно, они не являются частью объекта — память под объекты всегда выделяется на куче). Ограничения на структуры:
-
: 1. Структура не может быть явно унаследована ни от какого класса или структуры, при этом все структуры неявно наследуют object.
+
: 1. Структура не может наследоваться и не может быть явно унаследована. (Все структуры наследуют object)
: 2. В структуре нельзя явно определить конструктор умолчания, неявно определяемый конструктор заполняет структуру неопределенными значениями.
: 2. В структуре нельзя явно определить конструктор умолчания, неявно определяемый конструктор заполняет структуру неопределенными значениями.
-
;Типы значений (хранятся на стеке, если не являются полем класса):
+
;Референциальные типы
-
: Все базовые, кроме object и string.
+
: Классы, массивы. Располагаются только на куче.
-
: Перечисления (enum).
+
-
: Структуры (struct).
+
-
 
+
-
;Ссылочные типы<ref>Иногда говорят «референциальные типы», здесь использован вариант перевода из msdn.</ref> (значения, на которые указывает ссылочный тип (в частности, экземпляры классов), располагаются в куче):
+
-
: Класс.
+
-
: Массив (является объектом, экземпляром абстрактного класса Array).
+
-
: Интерфейс.
+
-
: И некоторые другие.
+
== Массивы ==
== Массивы ==
-
=== Длина массива статический или динамический атрибут ===
+
=== Длина массива - статический или динамический атрибут. ===
-
'''Си++''': длина массива - только статический атрибут. <br>
+
<b>Си++</b>: длина массива - только статический атрибут. <br>
-
'''Оберон''', '''Модула-2''': динамический атрибут только для формальных параметров, в остальных случаях - статический. <br>
+
<b>Оберон</b>, <b>Модула-2</b>: динамический атрибут только для формальных параметров, в остальных случаях - статический. <br>
-
'''Ада''', '''Java''', '''C#''': может быть и тем и другим. <br>
+
<b>Ада</b>, <b>Java</b>, <b>C#</b>: может быть и тем и другим. <br>
<br>
<br>
-
'''Замечание из методички''': <br>
+
<b>Замечание из методички</b>: <br>
в языках Оберон и Модула-2 длина формальных параметров — открытых массивов является динамическим атрибутом. <br>
в языках Оберон и Модула-2 длина формальных параметров — открытых массивов является динамическим атрибутом. <br>
В других случаях длина массива — статический атрибут. <br>
В других случаях длина массива — статический атрибут. <br>
В Аде формальные параметры неограниченных типов-массивов также имеют динамический атрибут-длину (равно как и динамические массивы-локальные переменные). <br>
В Аде формальные параметры неограниченных типов-массивов также имеют динамический атрибут-длину (равно как и динамические массивы-локальные переменные). <br>
<br>
<br>
-
'''Пример''' динамического массива в языке Java (или C#):
+
<b>Пример</b> динамического массива в языке Java (или C#): <br>
-
void f(int N) {
+
void f(int N) { <br>
-
byte [] dynArray = new byte [N];
+
byte [] dynArray = new byte [N]; <br>
-
// ...обработка ...
+
// ...обработка ... <br>
-
}
+
} <br>
=== ОБЕРОН И ОБЕРОН-2 ===
=== ОБЕРОН И ОБЕРОН-2 ===
Строка 319: Строка 231:
В Java явных указателей нет.
В Java явных указателей нет.
- 
-
== Преобразование типов ==
 
-
=== Явное преобразование типов ===
 
-
Преобразование типов называется ''явным,'' если оно указано программистом в исходном коде.
 
-
=== Неявное преобразование типов ===
 
- 
-
Преобразование типов называется ''неявным'', если оно не указывается программистом, но, тем не менее, выполняется (в языках со статической типизацией — соответствующие конструкции подставляются на этапе компиляции). В языках '''C'''<ref>Если не считать (T *) → (void *).</ref>, '''C#''', '''Java''', '''Pascal''', '''Delphi''', '''Modula-2''', '''Оберон''', '''Оберон-2''' неявными могут быть только расширяющие преобразования (иначе говоря, преобразования, к более общему типу<ref>Следует иметь ввиду, что в случае простых типов не всегда более общий тип может отобразить менее общий. К примеру, вещественный тип single стандарта IEEE 754 не может точно представить число 16777217, в то время как 32-битный целочисленный тип может.</ref>); в '''С++''' — любые преобразования. В языке '''Ада''' неявных преобразований почти<ref>Исключение составляет, например, неявное приведение числового литерала к конкретному типу. Подробнее: [http://www.adaic.org/resources/add_content/standards/05rm/html/RM-4-6.html#I2822].</ref> нет.
 
- 
-
==== Неявное преобразование для пользовательских классов ====
 
- 
-
Язык Java запрещает любые неявные преобразования между объектами классов (исключение составляют только неявные преобразования к стандартному типу String, разрешенные в некоторых
 
-
контекстах).
 
- 
-
Языки C++ и C# разрешают неявные преобразования для классов, определяемых пользователем.
 
- 
-
В '''C++''' преобразования определяются специальными функциями-членами: конструкторами преобразования и функциями преобразования. Конструктор преобразования имеет прототип вида:
 
-
Х(Т) // или Х(Т&) или X (const Т&)
 
- 
-
Функция преобразования имеет вид:
 
-
class X {
 
-
operator Т();
 
-
};
 
- 
-
В языке '''C#''' область применения пользовательских преобразований уже, чем в языке C++. Можно
 
-
определять свои преобразования только между двумя классами, нельзя определять преобразования в типы значений или из них. Преобразование из класса X в класс Y реализуется с помощью специального метода — функции преобразования:
 
-
static operator Y (X х) { ... }
 
-
Функция преобразования может быть только статическим методом либо класса х, либо класса Y. Если такая функция преобразования есть, то она вызывается с использованием обычного синтаксиса преобразований: (Y) х. Компилятор вставляет неявное преобразование из X в Y только, если соответствующая функция преобразования снабжена модификатором implicit:
 
-
static implicit operator Y (X x) { ... }
 
- 
-
Если же используется модификатор explicit, то функция преобразования может вызываться только явно. По умолчанию принимается модификатор explicit, что снижает вероятность случайной
 
-
ошибки.
 
- 
-
В '''Delphi''' есть неявное преобразование типов, работает для функций. Пример (не работает для Writeln, потому что это не функция, а конструкция языка):
 
-
 
-
program Overloads;
 
-
{$APPTYPE CONSOLE}
 
-
type
 
-
TRec = record
 
-
private
 
-
function GetOrd: Integer;
 
-
public
 
-
class operator Implicit(const Value: TRec): Integer;
 
-
property ord: Integer read GetOrd;
 
-
end;
 
-
 
-
class operator TRec.Implicit(const Value: TRec): Integer;
 
-
begin
 
-
Result := 0;
 
-
end;
 
-
 
-
function TRec.GetOrd: Integer;
 
-
begin
 
-
Result := 0;
 
-
end;
 
-
 
-
procedure Foo(i: Integer);
 
-
begin
 
-
end;
 
-
 
-
var
 
-
R: TRec;
 
-
a: array[0..0] of Integer;
 
-
 
-
begin
 
-
Writeln(R);//E2054 Illegal type in Write/Writeln statement
 
-
Writeln(Integer(R));//explicit cast, provided by class operator Implicit
 
-
Writeln(R.ord);//my preferred option, a property
 
-
a[R] := 0;//E2010 Incompatible types: 'Integer' and 'TRec'
 
-
a[Integer(R)] := 0;//again, explicit cast is fine
 
-
a[R.ord] := 0;//or using a property
 
-
Foo(R);//implicit cast used for actual parameters
 
-
end.
 
- 
-
=== Понятия ''conversion'' и ''casting'' ===
 
-
В большинстве языков, основанных на базе '''Algol''' и обладающих механизмом вложенных функций - например, в '''Ada, Delphi, Modula 2''' и '''Pascal,''' понятия ''conversion'' и ''casting'' принципиально различны. Понятие ''conversion'' относится к явному или неявному изменению значения одного типа данных на значение другого типа данных (например, расширение 16-битного целого до 32-битного). В этом случае, могут измениться требования к объёму выделенной памяти; могут возникнуть потери точности или округления. Понятие ''casting,'' напротив, обозначает ''явное'' изменение интерпретации ''последовательности бит.'' Например, последовательность из 32 бит может быть интерпретирована как целое без знака, как массив из 32 значений типа boolean или как вещественное число c одинарной точностью, соответствующее стандарту IEEE.
 
-
В '''C-подобных''' языках, понятием ''casting'' обозначается явное приведение типа в независимости от того, является ли оно изменением интерпретации последовательности бит, либо же настоящим преобразованием типа.
 
-
=== Упаковка и распаковка ===
 
-
Данные понятия определены для языков '''C#''' и '''Java.'''
 
-
: ''Упаковкой (boxing)'' называется процесс преобразования значения простого типа значения в экземпляр соответствующего класса-оболочки.
 
-
: ''Распаковкой (unboxing)'' называется, очевидно, процесс преобразования экземпляра класса-оболочки в значение соответствующего простого типа.
 
- 
-
==== C# ====
 
-
В '''C#''' упаковка и распаковка выполняются автоматически.
 
- 
-
Пример упаковки и распаковки:
 
-
int i = 123;
 
-
// The following line boxes i.
 
-
object o = i;
 
- 
-
o = 123;
 
-
i = (int) o; // unboxing
 
- 
-
==== Java ====
 
-
В '''Java''' автоупаковка и автораспаковка поддерживаются начиная с J2SE 5.0 (сентябрь 2004 года).
 
- 
-
Пример упаковки и распаковки:
 
-
int i = 123;
 
-
Integer boxedI = Integer.valueOf(i); // boxing
 
- 
-
Integer boxedI = Integer.valueOf(123);
 
-
int i = boxedI.intValue(); // unboxing
 
- 
-
==== Другие языки ====
 
- 
-
В некоторых языках упаковка и распаковка отсутствуют. Например, в '''Smalltalk''' любое значение принадлежит некоторому классу (т.е. даже значения простых типов являются экземплярами классов).
 
- 
-
В JavaScript ситуация несколько иная. Например, есть примитивный тип ''Number'' для чисел. В отличие от Java и C#, это тип является полноценным (к объектам этого типа можно применить операцию <code>typeof</code>). Однако при вызове методов примитивный тип упаковывается в объект, прототипом которого является <code>Number.prototype</code> (это не тот же самый ''Number''-примитивный тип!), и в котором уже определены нужные методы. Пример кода, который это демонстрирует:
 
-
<pre>
 
-
Number.prototype.test = function() { return this; }
 
-
var x = 5;
 
-
alert(x + " " + typeof x);
 
-
x = x.test();
 
-
alert(x + " " + typeof x);
 
-
</pre>
 
== Операторный базис языков программирования. Управление последовательностью вычислений ==
== Операторный базис языков программирования. Управление последовательностью вычислений ==
=== ADA ===
=== ADA ===
-
Примечание: в отличие от нижеследующих языков (таких как Pascal / Delphi и Modula-2), в ADA конструкция '''with''' не входит в операторный базис, а служит для подключения пакетов; см. [[#anchor_ada_with|раздел 7]].
+
Джентльменский набор:
 +
 
'''if''' condition '''then'''
'''if''' condition '''then'''
statement;
statement;
Строка 492: Строка 291:
Do_Something (I)
Do_Something (I)
'''end''' '''loop''' For_Loop;
'''end''' '''loop''' For_Loop;
- 
-
''(Замечание: именовать циклы необязательно.)''
 
=== ОБЕРОН И ОБЕРОН-2 ===
=== ОБЕРОН И ОБЕРОН-2 ===
-
Операторы в последовательности операторов идут через точку с запятой. В конце последовательности должна стоять точка.
+
ОператорIf =
-
 
+
-
Пайп-символы «|» — это обязательная деталь конструкций CASE и WITH (они разделяют альтернативные варианты, за исключением умолчательного, задаваемого после ключевого слова ELSE).
+
IF Выражение THEN ПоследовательностьОператоров
IF Выражение THEN ПоследовательностьОператоров
{ELSIF Выражение THEN ПоследовательностьОператоров}
{ELSIF Выражение THEN ПоследовательностьОператоров}
Строка 505: Строка 300:
CASE ch OF
CASE ch OF
-
"A" .. "Z": ReadIdentifier |
+
"A" .. "Z": ReadIdentifier
-
"0" .. "9": ReadNumber |
+
| "0" .. "9": ReadNumber
-
"'", '"': ReadString
+
| "'", '"' : ReadString
ELSE SpecialCharacter
ELSE SpecialCharacter
-
END.
+
END
WHILE Выражение DO
WHILE Выражение DO
Строка 519: Строка 314:
UNTIL Выражение.
UNTIL Выражение.
-
FOR v := начало TO конец BY шаг DO
+
FOR v := beg TO end BY step DO statements END (В Оберон-2)
-
ПоследовательностьОператоров
+
-
END.
+
-
''(* Присутствует только в Оберон-2 *)''
+
-
LOOP
+
LOOP ПоследовательностьОператоров END.
-
ПоследовательностьОператоров
+
-
END.
+
-
''(* Вечный цикл; для выхода используется ключевое слово EXIT *)''
+
-
WITH
+
WITH v: T1 DO S1 | v: T2 DO S2 ELSE S3 END (В Оберон-2)
-
Дискриминант: Значение1 DO ПоследовательностьОператоров1 |
+
-
Дискриминант: Значение2 DO ПоследовательностьОператоров2
+
-
ELSE ПоследовательностьОператоров3
+
-
END.
+
-
''(* Является подобием оператора CASE-OF по дискриминанту''
+
-
'' размеченного объединения; присутствует только в Оберон-2 *)''
+
-
 
+
-
=== Modula-2 ===
+
-
 
+
-
Полностью совпадает с Обероном-2, за исключением WITH, определяемого так:
+
-
WITH ПеременнаяСтруктурногоТипа DO
+
-
ПоследовательностьОператоров
+
-
Поле1:= Значение1;
+
-
ПоследовательностьОператоров
+
-
Поле2:= Значение2;
+
-
+
-
END.
+
-
''(* Поле1, Поле2, итд. — поля переменной «ПеременнаяСтруктурногоТипа»;''
+
-
'' конструкция с аналогичным поведением есть в Pascal и Delphi *)''
+
-
 
+
-
=== Pascal и Delphi ===
+
-
 
+
-
'''if''' condition1 '''then begin'''
+
-
statement1;
+
-
statement2;
+
-
+
-
'''end''' ''{ заметьте, точки с запятой нет }''
+
-
'''else if''' condition2 '''then begin'''
+
-
+
-
'''end'''
+
-
'''else begin'''
+
-
+
-
'''end'''; ''{ if-блок закончен, точка с запятой есть }''
+
-
 
+
-
'''case''' value1 '''of'''
+
-
constant1: '''begin'''
+
-
statement1;
+
-
statement2;
+
-
+
-
'''end''';
+
-
+
-
constant2: '''begin'''
+
-
+
-
'''end''';
+
-
+
-
+
-
+
-
'''else begin'''
+
-
+
-
'''end''';
+
-
'''end''';
+
-
 
+
-
'''goto''' label1; ''{ да, в стандарте Паскаля это было }''
+
-
+
-
never_executed_statement1;
+
-
never_executed_statement2;
+
-
+
-
+
-
label1:
+
-
 
+
-
'''for''' variable1 := constant1 '''to''' constant2 '''do begin'''
+
-
statement1;
+
-
statement2;
+
-
+
-
'''end'''; ''{ если constant1 > constant2, используется '''downto''' }''
+
-
 
+
-
'''while''' continuation '''do begin'''
+
-
statement1;
+
-
statement2;
+
-
+
-
'''end''';
+
-
 
+
-
'''repeat'''
+
-
statement1;
+
-
statement2;
+
-
+
-
'''until''' discontinuation;
+
-
''{ здесь, discontinuation означает условие останова, а не''
+
-
'' продолжения (как, например, в цикле предыдущего типа);''
+
-
'' также заметьте, что скобки '''begin''' / '''end''' тут не нужны }''
+
-
 
+
-
'''with''' struct1.substruct1.subsubstruct1 '''do begin'''
+
-
field1 = value1;
+
-
field2 = value2;
+
-
+
-
'''end;'''
+
-
''{ field1 и field2 — это поля структуры struct1.substruct1.subsubstruct1;''
+
-
'' в этом блоке они перекрывают собой любые переменные с теми же именами }''
+
-
 
+
-
=== C и C++ ===
+
-
 
+
-
if (condition1) {
+
-
statement1;
+
-
statement2;
+
-
+
-
}
+
-
else if (condition2) {
+
-
+
-
}
+
-
else {
+
-
+
-
}
+
-
 
+
-
return; ''// возврат из void-функции''
+
-
return value1; ''// возврат из функции, отдающей значение''
+
-
 
+
-
switch (value1) {
+
-
case constant1:
+
-
statement1;
+
-
statement2;
+
-
+
-
break;
+
-
+
-
case constant2:
+
-
+
-
break;
+
-
+
-
+
-
+
-
default:
+
-
+
-
break;
+
-
}
+
-
''// также вместо break можно использовать return (выходим не только из switch-блока, но и из функции).''
+
-
 
+
-
goto label1;
+
-
+
-
never_executed_statement1;
+
-
never_executed_statement2;
+
-
+
-
+
-
label1:
+
-
 
+
-
for (initializer; continuation; increment) {
+
-
statement1;
+
-
statement2;
+
-
+
-
}
+
-
''// любые из трёх выражений в заголовке цикла могут пустовать.''
+
-
''// например, for ( ; ; ) {} даст вечный цикл.''
+
-
 
+
-
do {
+
-
statement1;
+
-
statement2;
+
-
+
-
} while (continuation);
+
-
 
+
-
while (continuation) {
+
-
statement1;
+
-
statement2;
+
-
+
-
}
+
-
 
+
-
=== for в C# и Java ===
+
-
 
+
-
В '''Java''' используется 2 формы оператора цикла for.
+
-
Первая форма полностью соответствует оператору for языка Си++:
+
-
for (e1; e2; e3) S
+
-
Вторая форма появилась в J2SE 5.0 (вместе с generic'ами) и используется для поэлементного
+
-
просмотра коллекций (цикл for-each). Она имеет вид;
+
-
for (T v: Coll) S
+
-
Здесь Coll — коллекция элементов (типа T или приводимых к типу T).
+
-
Переменная v на каждой итерации цикла принимает значение очередного
+
-
элемента коллекции.
+
-
Для того, чтобы объекты класса-коллекции могли появляться в цикле
+
-
for-each, класс должен реализовать интерфейс Iterable.
+
-
 
+
-
Для того, чтобы for можно было аналогичным образом использовать в '''C#''', коллекция должна реализовывать интерфейс IEnumerable (конкретно метод GetEnumerator)
+
-
 
+
-
// метод класса, который мы хотим сделать итеративным
+
-
public System.Collections.IEnumerator GetEnumerator()
+
-
{
+
-
for (int i = 0; i < 10; i++)
+
-
{
+
-
yield return i;
+
-
}
+
-
}
+
-
 
+
-
Здесь yield преобразует int в объект класса IEnumerator. Кроме того, внутреннее состояние функции запоминается и в следующий раз выполнение функции будет продолжено с того состояния и места, где функция вышла в прошлый раз. yield может вызываться только в теле for.
+
== Процедурные абстракции ==
== Процедурные абстракции ==
- 
-
=== Передача параметров в подпрограммы ===
 
- 
-
Для каждой подпрограммы указывается набор формальных параметров. Можно рассматривать формальные параметры как локальные переменные тела подпрограммы. При вызове подпрограммы указывается список фактических параметров. Соответствие между фактическими и формальными параметрами выполняется по позиции в списке: первый фактический параметр соответствует первому формальному параметру и т. д. Такой способ называется ''позиционным''. Язык С#, начиная с версии 4, предусматривает альтернативный — ''ключевой'' способ отождествления, в котором используются имена формальных параметров, но мы не будем его рассматривать. Существует три вида формальных параметров:
 
-
* входные параметры (параметры, от которых требуется только значение). Мы используем только значения фактических параметров, которые не меняются при выходе из тела функции;
 
-
* выходные параметры (эти параметры не обязаны иметь начальное значение, но могут быть изменены в теле функции);
 
-
* изменяемые параметры (требуется и исходное значение, и возможность его изменения).
 
- 
-
С входным параметром может связываться произвольное выражение, а выходным или изменяемым — только объекты, которые могут стоять в левой части оператора присваивания. В большинстве языков программирования вместо указания вида параметра указывается способ (механизм) связывания параметра, называемый способом передачи параметра.
 
- 
-
Существует два основных способа передачи параметров: ''по значению'' и ''по ссылке''.
 
- 
-
==== Передача параметров по значению ====
 
- 
-
Формальный параметр есть некоторая локальная переменная. Место для локальных переменных отводится в стеке. При вызове подпрограммы значение фактического параметра копируется в соответствующий формальный параметр. Все изменения формального параметра связаны с изменением локальной переменной и не сказываются на фактическом параметре. Перед копированием может потребоваться приведение типа, если типы фактического и формального параметров не совпадают.
 
- 
-
==== Передача параметров по ссылке ====
 
- 
-
Фактически этот способ есть передача ссылки по значению. Формальный параметр — это ссылка на объект. (Существует мнение, что данное «определение» не только не отражает сути явления, но и неверно в корне. В дискуссии вокруг передачи аргументов в Java Dale King [http://www.yoda.arachsys.com/java/passing.html дал] следующее определение. ''Передача по ссылке — это когда lvalue формального параметра устанавливается в lvalue фактического параметра.'') В момент вызова происходит инициализация ссылки фактическим параметром. Преобразования типов в этот момент не происходит: типы формального и фактического параметров должны совпадать. Поскольку ссылка после инициализации отождествляется с объектом, то любые изменения формального параметра подразумевают изменения фактического параметра. Очевидно, что способ передачи по значению соответствует семантике входных формальных параметров. По ссылке можно передавать выходные и изменяемые параметры.
 
- 
-
==== Аргументы в C/C++ всегда передаются по значению ====
 
- 
-
В C++ есть ссылочный тип. Переменная ссылочного типа может ссылаться на значение любого типа, должна быть инициализирована и не может менять значения. С помощью передачи переменной ссылочного типа можно имитировать все возможности контрукции var из '''Pascal'''. Но можно действовать в стиле C — передавать указатель. В свою очередь, чтобы менять указатель, можно передавать в функцию/метод указатель или ссылку на него.
 
- 
-
==== Аргументы в Java всегда передаются по значению ====
 
- 
-
Существует распространённое '''заблуждение''' о том, что «объекты передаются по ссылке, а примитивные типы — по значению».
 
-
'''На самом деле''' ситуация иная:
 
-
# Аргументы любого типа передаются по значению. Объекты, однако, не передаются вообще.
 
-
# Значения переменных всегда примитивы или ссылки (или null), но никак не объекты.
 
-
Подробнее см. http://www.yoda.arachsys.com/java/passing.html .
 
- 
-
В соответствии с изложенным выше, метод может изменить объект через аргумент-ссылку. С примитивным типом это не пройдёт, так как в Java нет ссылок на значения примитивных типов. Чтобы иметь возможность изменить из метода значение некоторой внешней переменной примитивного типа, нужно чтобы эта переменная была полем некоторого объекта.
 
- 
-
В связи с этим для примитивных типов были введены классы-обёртки. Объект такого класса содержит в себе значение примитивного типа, которое можно как прочитать, так и поменять. См. также [[Сравнение_Языков_Программирования#.D0.A3.D0.BF.D0.B0.D0.BA.D0.BE.D0.B2.D0.BA.D0.B0_.D0.B8_.D1.80.D0.B0.D1.81.D0.BF.D0.B0.D0.BA.D0.BE.D0.B2.D0.BA.D0.B0|Упаковка и распаковка]]
 
=== Перегрузка операций ===
=== Перегрузка операций ===
Ада 83, Ада 95, Си++, Java, Delphi, C#
Ада 83, Ада 95, Си++, Java, Delphi, C#
-
Понятие «перегрузка» (англ. overloading) означает, что одному имени в одной области видимости может соответствовать несколько определений. В современных языках программирования перегружаться могут только имена подпрограмм, но не типов, переменных, модулей.
+
Понятие «перегрузка» означает, что одному имени в одной области
-
 
+
видимости может соответствовать несколько определений. В современных
-
Пример на языке C++:
+
языках программирования перегружаться могут только имена подпрограмм,
 +
но не типов, переменных, модулей.
 +
Пример на языке Си++:
class X {
class X {
public:
public:
void f();
void f();
-
void f(int)
+
void f (int)
};
};
Строка 763: Строка 340:
a.f(0); // вторая функция
a.f(0); // вторая функция
-
Отличие перегрузки от замещения (скрытие, англ. hide) состоит во-первых, в том, что перегрузка обрабатывается статически (на этапе трансляции) (а замещение?), в во-вторых, при замещении речь идет о разных областях видимости: базовый класс с объявлением виртуального метода (объемлющая область видимости) и производный класс с замещающим методом (вложенная область видимости).
+
Отличие перегрузки от замещения состоит во-первых, в том, что
 +
перегрузка обрабатывается статически (на этапе трансляции), в во-вторых,
 +
при замещении речь идет о разных областях видимости: базовый класс с
 +
объявлением виртуального метода (объемлющая область видимости) и
 +
производный класс с замещающим методом (вложенная область видимости).
=== ADA ===
=== ADA ===
Строка 780: Строка 361:
=== ОБЕРОН И ОБЕРОН-2 ===
=== ОБЕРОН И ОБЕРОН-2 ===
Имеются два вида процедур: собственно процедуры и процедуры- функции. Последние активизируются обозначением функции как часть выражения и возвращают результат, который является операндом выражения. Собственно процедуры активизируются вызовом процедуры. Процедура является процедурой-функцией, если ее формальные параметры задают тип результата. Тело процедуры-функции должно содержать оператор возврата, который определяет результат.
Имеются два вида процедур: собственно процедуры и процедуры- функции. Последние активизируются обозначением функции как часть выражения и возвращают результат, который является операндом выражения. Собственно процедуры активизируются вызовом процедуры. Процедура является процедурой-функцией, если ее формальные параметры задают тип результата. Тело процедуры-функции должно содержать оператор возврата, который определяет результат.
- 
-
PROCEDURE log2 (x: INTEGER): INTEGER;
 
-
VAR y: INTEGER; (*предполагается x>0*)
 
-
BEGIN
 
-
y := 0; WHILE x > 1 DO x := x DIV 2; INC(y) END;
 
-
RETURN y
 
-
END log2
 
== Определение новых типов данных. Логические модули. Классы ==
== Определение новых типов данных. Логические модули. Классы ==
Строка 861: Строка 435:
При подключении потомка родитель-пакет подключается автоматически.
При подключении потомка родитель-пакет подключается автоматически.
-
<div id="anchor_ada_with"></div>О подключениях. Подключить пакет можно с помощью конструкции '''with'''.
+
О подключениях. Подключить пакет можно с помощью конструкции '''with'''.
'''with''' Points.RandomDistributions;
'''with''' Points.RandomDistributions;
После этого можно будет пользоваться ввсем, что в пакете лежит, через точечную нотацию. Если же вызовов слишком много, то можно влить содержимое пакета в текущую область видимости с помощью '''use''' (только после подключения!).
После этого можно будет пользоваться ввсем, что в пакете лежит, через точечную нотацию. Если же вызовов слишком много, то можно влить содержимое пакета в текущую область видимости с помощью '''use''' (только после подключения!).
Строка 900: Строка 474:
valn: typen;
valn: typen;
END;
END;
- 
-
=== Namespace в C# ===
 
- 
-
Ключевое слово namespace используется для объявления области, которая содержит набор связанных объектов. Можно использовать пространство имён для организации элементов кода, а также для создания глобально уникальных типов.
 
-
namespace SampleNamespace
 
-
{
 
-
class SampleClass { }
 
-
 
-
interface SampleInterface { }
 
-
 
-
struct SampleStruct { }
 
-
 
-
enum SampleEnum { a, b }
 
-
 
-
delegate void SampleDelegate(int i);
 
-
 
-
namespace SampleNamespace.Nested
 
-
{
 
-
class SampleClass2 { }
 
-
}
 
-
}
 
=== Классы ===
=== Классы ===
==== Конструкторы ====
==== Конструкторы ====
-
Обычно выделяют следующие типы конструкторов: конструктор по умолчанию, конструктор копирования и конструктор преобразования. Конструкторы имеют пользовательскую (тело объявленного конструктора) и системную (сгенерированный код) части.
+
Обычно выделяют следующие типы конструкторов: конструктор по умолчанию, конструктор копирования и конструктор преобразования.
-
 
+
-
==== Деструкторы и финализаторы ====
+
-
Деструкторы и финализаторы — это специальные функции-члены класса, автоматически вызываемые при уничтожении объекта класса. Роль деструкторов и финализаторов — освобождение захваченных объектом ресурсов. Если объект не захватывает ресурсы или ресурсы освобождаются автоматически, то нужды в деструкторе (финализаторе) нет. Деструкторы ''не имеют'' параметров. В языке Java деструкторов нет, их роль (до определенной степени)
+
-
играет метод void finalize() — финализатор. В языке '''C#''' формально деструкторы есть, однако их поведение аналогично поведению финализаторов
+
-
в языке '''Java'''.
+
-
Деструкторы в '''C++''' отличаются от финализаторов в '''Java''' и '''C#''' тем, что в '''C++''' можно достаточно точно установить момент вызова деструктора.
+
-
# Деструкторы статических объектов вызываются после выхода из функции main.
+
-
# Деструкторы квазистатических объектов выполняются при выходе из блока. Причём, деструкторы вызываются строго в обратном порядке относительно порядка вызова конструкторов квазистатических объектов данного блока.
+
-
# Деструкторы динамических объектов выполняются при вызове операции delete.
+
-
# Деструкторы временных объектов выполняются при выходе из конструкции, в контексте которой был создан объект.
+
-
В '''Java''' и '''C#''' время вызова финализатора не определено из-за наличия сборщика мусора.
+
-
Как и конструкторы, деструкторы имеют пользовательскую и системную части.
+
-
 
+
-
==== Неявные контрукторы/деструкторы/операции в C++ ====
+
-
 
+
-
Следующие элементы класса могут быть определены неявно:
+
-
* Конструктор по умолчанию (если нет ни одного явно определённого конструктора).
+
-
* Конструктор копирования (если конструктор копирования не описан явно). Осуществляет т.н. поверхностное копирование полей класса (бит в бит).
+
-
* Деструктор (если деструктор не описан явно). Вызывает деструкторы объектов-полей (не полей-указателей!).
+
-
* Операция присваивания (если не определена явно). Записывает значения полей объекта-аргумента в целевой объект (тоже поверхностное копирование), возвращает ссылку на целевой объект.
+
-
Фишки:
+
==== Деструкторы ====
-
* Запрет копирования объекта: определить конструктор копирования в приватной части класса.
+
Деструкторы в C++ отличаются от деструкторов в Java и C# тем, что в C++ примерно установлено место в программе, в котором будет вызван деструктор (для объектов, выделенных в статической или квазистатической памяти) или он будет вызван вручную. В Java и C# время вызова деструктора не определено из-за наличия сборщика мусора.
-
* Запрет создания экземпляровобъекта — глобальных и локальных переменных, иначе говоря данные запрещено размещать в секциях .data/.bss и на стеке, разрешено только в динамической памяти. Нужно определить декструктор в приватной части класса. Освобождение ресурсов объекта при таком подходе осуществляется через метод данного класса.
+
-
* Запрет присваивания одного объекта другому: определение операции присваивания в приватную часть класса.
+
-
* Запрет неявного вызова конструктора копирования, конструктора преобразования (иначе говоря, конструкторов с одним параметром) или операции преобразования (последнее — только в C++11). Нужно добавить в начало заголовка ключевое слово explicit.
+
==== Свойства ====
==== Свойства ====
Строка 999: Строка 529:
end;
end;
-
==== Статические классы ====
+
== Инкапсуляция и абстрактные типы данных ==
-
 
+
===ОБЕРОН И ОБЕРОН-2===
-
''Статический класс'' — это, в общем случае, достаточно неформальное понятие. Обычно так называют класс, все члены которого объявлены статическими. Для работы с таким классом не требуется создавать экземпляр и часто, говоря о статическом классе, подразумевают невозможность создания экземпляра. Такой класс, как правило, не имеет конструкторов и деструкторов, либо они объявлены приватными (в зависимости от языка).<ref>Стоит уточнить, что статический класс в C# может иметь статический конструктор, см. далее раздел про C#.</ref>
+
Позволяют открывать поля структуры
-
 
+
-
Иногда понятие ''статического класса'' закрепляется на уровне языка программирования. В этом случае язык добавляет некоторые требования, кроме статичности всех членов и невозможности создания экземпляров: например, невозможность наследования от данного класса или невозможность реализации таким классом интерфейса (см. далее про C#).
+
-
 
+
-
Следует понимать, что в контексте разных языков программирования могут подразумеваться разные понятия статического класса, разной степени формальности (вплоть до строго закреплённого языком понятия).
+
-
 
+
-
===== В C++ =====
+
-
 
+
-
В C++ понятие статического класса отсутствует. Для реализации статического класса нужно объявить члены класса статическими (static) и запретить создание его экземпляров, поместив конструктор по умолчанию и конструктор копирования в приватную (private) часть класса (а по-хорошему, ещё и деструктор). Похожих свойств можно добиться, используя шаблон проектирования singleton — для класса-singleton'а будет существовать ''ровно один'' экземпляр данного класса.
+
-
 
+
-
===== В Java =====
+
-
 
+
-
В Java также нет понятия соответствующего статическому классу в данном выше понимании (статические вложенные классы — совершенно другая вещь, о них далее в этом разделе). Ситуация аналогична ситуации в C++. Для реализации статического класса нужно объявить все члены статическими (static) и запретить создание его экземпляров, объявив конструктор приватным (private). Чтобы ближе имитировать статический класс C# можно отказаться от наследования с помощью ключевого слова ''final''. Похожих свойств можно добиться используя шаблон проектирования singleton.
+
-
 
+
-
В Java существует модификатор static для класса, но применяться он может '''только''' ко вложенным (nested) классам. Статический вложенный класс нельзя считать статическим в том смысле, который вкладывается в это понятие в начале данного раздела и далее в разделе про Java этот смысл не подразумевается.
+
-
 
+
-
Вложенные классы делятся на две категории — статические и нестатические. Вложенные классы, объявленные статическими называются статическими вложенными классами (static nested classes). Нестатические вложенные классы называются внутренними (inner classes). Ко вложенному классу могут быть применены любые модификаторы доступа (тогда как к классу верхнего уровня — только ''public'' или ''package private'').
+
-
 
+
-
'''class''' OuterClass {
+
-
...
+
-
'''static''' '''class''' StaticNestedClass {
+
-
...
+
-
}
+
-
'''class''' InnerClass {
+
-
...
+
-
}
+
-
}
+
-
 
+
-
Статический вложенный класс может использоваться без экземпляра объемлющего класса. Он взаимодействует с членами объемлющего класса (и любого другого) точно так же как любой класс верхнего уровня (не вложенный). В сущности, он ведёт себя как класс верхнего уровня, вложенный в другой лишь с точки зрения логической группировки классов.
+
-
 
+
-
// Создание экземпляра статического вложенного класса.
+
-
OuterClass.StaticNestedClass nestedObject =
+
-
'''new''' OuterClass.StaticNestedClass();
+
-
 
+
-
Внутренний класс имеет доступ ко всем членам объемлющего класса, даже если они объявлены с модификатором ''private'' и не может содержать статические члены. Экземпляр внутреннего класса можно получить только от конкретного экземпляра объемлющего класса. Можно сказать, что каждый из экземпляров внутреннего класса ведёт себя как часть соответствующего экземпляра объемлющего класса.
+
-
 
+
-
// Создание экземпляра внутреннего класса.
+
-
OuterClass.InnerClass innerObject =
+
-
outerObject.'''new''' InnerClass();
+
-
 
+
-
Больше информации:
+
-
* http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
+
-
* http://stackoverflow.com/questions/3584113/java-static-class
+
-
 
+
-
===== В C# =====
+
-
 
+
-
В C# существует понятие статического класса. Статический класс создаётся с помощью ключевого слова ''static''. Компилятор предоставляет относительно такого класса некоторые гарантии.
+
-
 
+
-
* Может содержать только статические члены.
+
-
* Нельзя создать экземпляр такого класса.
+
-
* Неявно определяется как ''sealed'', т.е. наследоваться от такого класса нельзя.
+
-
* Не может иметь instance constructors.
+
-
* Может иметь статический конструктор, который выполняется перед первым обращением к данному классу.
+
-
* Не может быть унаследован ни от какого объекта, исключая Object, от которого, как и все классы, наследуется неявно.
+
-
 
+
-
Также можно обратить внимание на тот факт, что к члену интерфейса не может быть применено ключевое слово ''static'', равно как и к соответствующему члену реализующего интерфейс класса. Напрямую к статическим классам это не относится, но означает, что реализовать интерфейс с хотя бы одним членом статический класс не может. Вопрос о том, может ли статический класс быть реализацией интерфейса без членов остаётся в рамках данной статьи открытым, профессионалы могут добавить ответ и ссылку на него.
+
-
 
+
-
Больше информации:
+
-
* [http://msdn.microsoft.com/en-us/library/79b3xss3.aspx Msdn: «Static Classes and Static Class Members (C# Programming Guide)»].
+
-
* [http://msdn.microsoft.com/en-us/library/ms173156.aspx Msdn: «Interfaces (C# Programming Guide)»].
+
-
* http://stackoverflow.com/questions/259026/why-doesnt-c-sharp-allow-static-methods-to-implement-an-interface
+
-
 
+
-
=== Объединение типов (запись с вариантами) ===
+
-
 
+
-
Объединение типов (или запись с вариантами) — это конструкция, объединяющая в один тип несколько различных структур (вариантов). Все варианты в объединении начинаются с одного адрес и занимают одну и ту же память.
+
-
 
+
-
Размеченное объединение типов содержит одно выделенное поле (дискретного типа данных) — общее для всех вариантов. Такое поле называется дискриминантом. Значение дискриминанта определяет, по какому варианту выделена память в переменной-экземпляре размеченного объединения.
+
-
 
+
-
=== Семантика копирования ===
+
-
 
+
-
Проблема копирования состоит в том, что копируемый объект может содержать ссылки на другие объекты. Проблема копирования состоит в том, что объекты могут содержать ссылки на другие объекты. При копировании таких ссылок возникает дилемма: копировать либо только ссылку, либо полностью
+
-
содержимое объекта, на который указывает ссылка. Первый вид копирования называется ''поверхностным'', а второй — ''глубоким.'' В общем случае транслятор не в состоянии выбрать нужную семантику копирования, поэтому в языках программирования, которые мы рассматриваем, принята следующая схема: по умолчанию реализуется ''поверхностное копирование,'' но программисту предоставляются средства для указания ''глубокой семантики копирования.'' В '''C++''' этими средствами являются переопределение конструктора копирования и операции присваивания, в '''Java''' и '''C#''' — наследование и реализация специального интерфейса.
+
-
 
+
-
==== Особенности копирования объектов в Java ====
+
-
 
+
-
Все массивы реализуют интерфейс Cloneable и могут копироваться. Поэтому далее рассматриваются только экземпляры классов.
+
-
 
+
-
Для того, чтобы разрешить копировать экземпляр класса в Java нужно сделать следующее:
+
-
# Реализовать интерфейс Cloneable. Этот интерфейс не содержит методов и служит только для того, чтобы указать, что вы разрешаете копировать этот объект.
+
-
# Переопределить метод clone класса Object со спецификатором доступа public. Заголовок метода в Object выглядит так:<br /><tt>protected Object clone() throws CloneNotSupportedException</tt><br />Object.clone() выбрасывает исключение CloneNotSupprotedException только в случае, если не реализован интерфейс Cloneable. Однако, переопределяющий метод может выбрасывать исключение CloneNotSupportedException для того, чтобы показать, что объект не может или не должен быть скопирован.
+
-
# По соглашению, переопределяющий метод должен получать копию объекта с помощью вызова метода clone суперкласса (конструкция super.clone()). Object.clone() возвращает новый объект со значениями полей, в точности равными соответствующим значениям переданного в параметре объекта (поверхностное копирование).
+
-
# Если требуется глубокое копирование, то перед тем, как вернуть объект-копию, нужно привести его к соответствующему типу и заменить значения необходимых полей вручную созданными копиями.
+
-
 
+
-
Больше информации:
+
-
* http://docs.oracle.com/javase/7/docs/api/java/lang/Cloneable.html
+
-
* http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#clone%28%29
+
-
* http://docs.oracle.com/javase/7/docs/api/java/lang/CloneNotSupportedException.html
+
-
 
+
-
И. Г. Головин выделяет не два (копируется / не копируется) вида копирования в Java, а четыре. ЕМНИП, добавляется вариант с перманентным выбросом исключения CloneNotSupportException для явного запрета копирования. А четвёртый не помню. ''TODO: описать все варианты.''
+
-
 
+
-
В общем случае всё это говорит о сложности проблемы копирования. Проблемы у программистов на '''C#''' — такие же.
+
== Модульность и раздельная трансляция ==
== Модульность и раздельная трансляция ==
Строка 1205: Строка 645:
=== ADA ===
=== ADA ===
-
Ада, наверное - единственный язык со вложенностью модулей, их раздельной компиляцией и двойной связью одновременно.
 
-
Опишем вложенную спецификацию, тут ничего сложного:
 
- 
-
'''package''' Outer '''is'''
 
-
'''...'''
 
-
'''procedure''' some_proc (X: Some_type) '''is private;'''
 
-
'''package''' Inner '''is'''
 
-
'''...''' ''-- Тут, в общем то видно все, что есть в пакете Outer.
 
-
'''end''' Inner;
 
-
'''...'''
 
-
'''end''' Outer;
 
- 
-
Тела этих пакетов, как и тело функции, можно разнести по разным файлам (единицам компиляции), используя "заглушку" '''separate''':
 
- 
-
'''package''' '''body''' Outer '''is'''
 
-
'''...'''
 
-
'''package''' Inner '''is''' '''separate''';
 
-
'''...'''
 
-
'''procedure''' some_proc (X: some_type) '''is''' '''separate''';
 
-
'''end''' Outer;
 
- 
-
Теперь опишем тела модуля Inner и процедуры.
 
- 
-
'''separate''' (Outer) ''--Тут нет `;' ''
 
-
'''package''' '''body''' Inner '''is'''
 
-
'''...'''
 
-
'''end''' Inner;
 
- 
-
'''separate''' (Outer)
 
-
'''procedure''' some_proc (X: some_type) '''is'''
 
-
'''...'''
 
-
'''end''' some_proc;
 
- 
-
Вот здесь заглушка '''separate''' и является двойной модульной связью.
 
== Исключительные ситуации и обработка ошибок ==
== Исключительные ситуации и обработка ошибок ==
- 
-
; Зачечание
 
-
: Кроме перечисленных в итоговой таблице языков исключения поддерживает Visual Basic.
 
=== Исключения и блоки try {} catch {} finally {}. Семантика возобновления и семантика завершения. ===
=== Исключения и блоки try {} catch {} finally {}. Семантика возобновления и семантика завершения. ===
Строка 1304: Строка 707:
// Может выбрасывать любые исключения.
// Может выбрасывать любые исключения.
-
Данные конструкции служат для того, чтобы показать программисту и компилятору, что данный метод (или, в случае C++, метод или функция) может выбрасывать исключения соответствующих типов. Насколько [[Участник:Totktonada|я]] понимаю, всё это влияет только на статические проверки компилятора и эстетические чувства программиста. В runtime эти декларации никак себя не проявляют, поэтому употребляемые здесь «может / не может выбрасывать исключение данного типа» и тому подобные обороты следует понимать в контексте статических проверок. ''(Замечание: не совсем верно. Исключения могут возникнуть в виртуальной функции или в отдельно оттранслированной. Memento std::unexpected().)''
+
Данные конструкции служат для того, чтобы показать программисту и компилятору, что данный метод (или, в случае C++, метод или функция) может выбрасывать исключения соответствующих типов. Насколько [[Участник:Totktonada|я]] понимаю, всё это влияет только на статические проверки компилятора и эстетические чувства программиста. В runtime эти декларации никак себя не проявляют, поэтому употребляемые здесь «может / не может выбрасывать исключение данного типа» и тому подобные обороты следует понимать в контексте статических проверок.
В Java считается, что метод, выбрасывающий исключение должен обозначить это с помощью конструкции throws. Иначе говоря, считается, что если директивы throws нет, то метод не выбрасывает исключений. Компилятор делает некоторые статические проверки, по крайней мере, запрещает выбрасывать исключения, не перечисленные в throws, явно — с помощью оператора throw.
В Java считается, что метод, выбрасывающий исключение должен обозначить это с помощью конструкции throws. Иначе говоря, считается, что если директивы throws нет, то метод не выбрасывает исключений. Компилятор делает некоторые статические проверки, по крайней мере, запрещает выбрасывать исключения, не перечисленные в throws, явно — с помощью оператора throw.
В C++, в отличие от Java, если директива throw не задана, то считается, что данный метод или функция может выбрасывать любые исключения. Статические (времени компиляции) проверки делаются только для тех методов/функций, для которых указан (возможно пустой) список исключений.
В C++, в отличие от Java, если директива throw не задана, то считается, что данный метод или функция может выбрасывать любые исключения. Статические (времени компиляции) проверки делаются только для тех методов/функций, для которых указан (возможно пустой) список исключений.
- 
-
=== Одно из заданий экзамена по ЯПам ===
 
- 
-
2004 г, задание 8. Смоделируйте на языке Си++ функцию
 
-
void f() throw (E1,E2,E3) { g(); h(); }
 
-
предполагая, что конструкция throw<ref>Видимо, подразумевается конструкция throw (…) в заголовке метода/функции, а не выбрасывание (или повторное выбрасывание) исключения с помощью оператора throw.</ref> не допускается компилятором.
 
-
 
-
void f()
 
-
{
 
-
try {
 
-
g(); h();
 
-
} catch (E1) {
 
-
throw;
 
-
} catch (E2) {
 
-
throw;
 
-
} catch (E3) {
 
-
throw;
 
-
} catch (...) {
 
-
unexpected();
 
-
}
 
-
}
 
=== ADA ===
=== ADA ===
Строка 1349: Строка 731:
Do_Smth;
Do_Smth;
'''end''';
'''end''';
 +
 +
'''finally-блока в Аде таки нету.''' Однако он [http://stackoverflow.com/questions/4804135/best-practice-for-implementing-in-ada-2005-or-2012-an-equivalent-of-the-java-f имитируется].
Отлов исключения так же может иметь такой вид:
Отлов исключения так же может иметь такой вид:
Строка 1357: Строка 741:
== Наследование типов и классов ==
== Наследование типов и классов ==
- 
-
=== C# и Java ===
 
- 
-
В C# и Java можно в дочернем классе сослаться на экземпляр родительского с помощью ключевых слов '''base''' (C#) и '''super''' (Java).
 
- 
-
Кроме того, в этих языках есть ключевые слова '''sealed''' (C#) и '''final''' (Java). Они могут находиться в заголовке<ref>Вероятно, только перед определением типа.</ref> метода (в случае C# — только виртуального) или класса ('''final''' также может находиться в описании поля, но это «другая песня»).
 
- 
-
В C# '''sealed''' в заголовке виртуального метода означает запрет перегрузки (англ. override) метода в производных классах. В заголовке класса — запрет наследования от данного класса.
 
- 
-
В Java '''final''' в заголовке метода означает, запрет замещения (скрытия, англ. hide) или перегрузки (англ. override) метода в производных классах. В заголовке класса — запрет наследования от данного класса.
 
=== ADA ===
=== ADA ===
Строка 1392: Строка 766:
'''end Person''';
'''end Person''';
-
ООП в Аде является вполне полноценным c Динамическим полиморфизмом, [http://esyr.org/wiki/%D0%A1%D1%80%D0%B0%D0%B2%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%AF%D0%B7%D1%8B%D0%BA%D0%BE%D0%B2_%D0%9F%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F#ADA_8 RTTI], абстрактными типами и интерфейсами.
+
ООП в Аде является вполне полноценным c Динамическим полиморфизмом, RTTI, абстрактными типами и интерфейсами.
== Динамический полиморфизм ==
== Динамический полиморфизм ==
-
В объектно-ориентированных языках программирования динамический полиморфизм реализуется с помощью наследования классов и виртуальных функций и/или виртуальных членов. Класс-потомок наследует сигнатуры методов класса-родителя, а реализация, в результате переопределения метода, этих методов может быть другой, соответствующей специфике класса-потомка. Другие функции могут работать с объектом как с экземпляром класса-родителя, но если при этом объект на самом деле является экземпляром класса-потомка, то во время исполнения будет вызван метод, переопределенный в классе-потомке. Это называется поздним связыванием.
+
В оо яп полиморфизм реализуется с помощью наследования классов и виртуальных функций. Класс-потомок наследует сигнатуры методов класса-родителя, а реализация, в результате переопределения метода, этих методов может быть другой, соответствующей специфике класса-потомка. Другие функции могут работать с объектом как с экземпляром класса-родителя, но если при этом объект на самом деле является экземпляром класса-потомка, то во время исполнения будет вызван метод, переопределенный в классе-потомке. Это называется поздним связыванием.
Позднее связывание есть в C++, C#, Java, Delphi, Ада 95, Оберон-2.
Позднее связывание есть в C++, C#, Java, Delphi, Ада 95, Оберон-2.
- 
-
=== C# ===
 
-
В '''C#''' к динамическому полиморфизму имеют отношение 3 важных ключевых слова (модификатора):
 
-
: 1. '''virtual'''
 
-
: 2. '''override'''
 
-
: 3. '''new'''
 
- 
-
==== virtual ====
 
-
Ключевое слово '''virtual''' используется для изменения объявлений методов, свойств, индексаторов и событий и разрешения их переопределения в производном классе. Например, этот метод может быть переопределен любым производным классом. Модификатор '''virtual''' нельзя использовать с модификаторами '''static, abstract, private''' или '''override.'''
 
- 
-
public virtual double Area()
 
-
{
 
-
return x * y;
 
-
}
 
- 
-
==== override ====
 
-
Модификатор '''override''' требуется для расширения или изменения абстрактной или виртуальной реализации унаследованного метода, свойства, индексатора или события. Иными словами, модификатор '''override''' ''расширяет'' метод базового класса. Метод, переопределенный c использованием '''override,''' называется переопределенным базовым методом. Переопределенный базовый метод должен иметь ту же сигнатуру, что и метод '''override.''' Невиртуальный или статический метод нельзя переопределить. Переопределенный базовый метод должен иметь тип '''virtual, abstract''' или '''override.''' Объявление '''override''' не может изменить уровень доступа метода '''virtual.''' Методы '''override''' и '''virtual''' должны иметь одинаковый модификатор уровня доступа.
 
-
Модификаторы '''new, static''' и '''virtual''' нельзя использовать для изменения метода '''override.'''
 
-
Переопределяющее объявление свойства должно задавать такие же модификаторы уровня доступа, тип и имя, как и имеющиеся у унаследованного свойства, а переопределенное свойство должно иметь тип '''virtual, abstract''' или '''override.'''
 
- 
-
class BaseClass
 
-
{
 
-
public virtual void Method1()
 
-
{
 
-
Console.WriteLine("Base - Method1");
 
-
}
 
-
public void Method2()
 
-
{
 
-
Console.WriteLine("Base - Method2");
 
-
}
 
-
}
 
-
class DerivedClass : BaseClass
 
-
{
 
-
public override void Method1()
 
-
{
 
-
Console.WriteLine("Derived - Method1");
 
-
}
 
-
public void Method2()
 
-
{
 
-
Console.WriteLine("Derived - Method2");
 
-
}
 
-
}
 
-
// ...
 
-
BaseClass bc = new BaseClass();
 
-
DerivedClass dc = new DerivedClass();
 
-
BaseClass bcdc = new DerivedClass();
 
-
bc.Method1();
 
-
bc.Method2();
 
-
dc.Method1();
 
-
dc.Method2();
 
-
bcdc.Method1();
 
-
bcdc.Method2();
 
-
// Output:
 
-
// Base - Method1
 
-
// Base - Method2
 
-
// Derived - Method1
 
-
// Derived - Method2
 
-
// Derived - Method1
 
-
// Base - Method2
 
- 
-
==== new ====
 
-
Модификатор '''new''' ''скрывает'' члены, унаследованные от базового класса. При сокрытии унаследованного члена его производная версия заменяет версию базового класса. (На самом деле, члены можно скрыть и без модификатора '''new,''' но в результате возникнет предупреждение. Если же для явного скрытия члена используется '''new,''' то модификатор отключает вывод предупреждений и документирует тот факт, что производная версия предназначена для замены.
 
- 
-
class BaseClass
 
-
{
 
-
public void Method1()
 
-
{
 
-
Console.WriteLine("Base - Method1");
 
-
}
 
-
public void Method2()
 
-
{
 
-
Console.WriteLine("Base - Method2");
 
-
}
 
-
}
 
-
class DerivedClass : BaseClass
 
-
{
 
-
public override void Method1()
 
-
{
 
-
Console.WriteLine("Derived - Method1");
 
-
}
 
-
public new void Method2()
 
-
{
 
-
Console.WriteLine("Derived - Method2");
 
-
}
 
-
}
 
-
// ...
 
-
BaseClass bc = new BaseClass();
 
-
DerivedClass dc = new DerivedClass();
 
-
BaseClass bcdc = new DerivedClass();
 
-
bc.Method1();
 
-
bc.Method2();
 
-
dc.Method1();
 
-
dc.Method2();
 
-
bcdc.Method1();
 
-
bcdc.Method2();
 
-
// Output:
 
-
// Base - Method1
 
-
// Base - Method2
 
-
// Base - Method1
 
-
// Derived - Method2
 
-
// Base - Method1
 
-
// Base - Method2
 
== Абстрактные типы данных, классы и интерфейсы ==
== Абстрактные типы данных, классы и интерфейсы ==
-
Абстрактный тип данных (АТД) — это тип с полностью инкапсулированной структурой. Использовать объекты АТД возможно только при помощи явно определенных в интерфейсе типа операций. Абстрактный класс (АК) — это класс, содержащий хотя бы один абстрактный метод. Он предназначен только для того, чтобы быть базовым классом.
+
Абстрактный тип данных (АТД) — это тип с полностью
 +
инкапсулированной структурой. Использовать объекты АТД возможно
 +
только при помощи явно определенных в интерфейсе типа операций.
 +
Абстрактный класс (АК) — это класс, содержащий хотя бы один
 +
абстрактный метод. Он предназначен только для того, чтобы быть базовым классом.
-
Прямой связи между АК и АТД нет. АТД может быть абстрактным классом, а может и не быть. Аналогично, АК может иметь инкапсулированную структуру, а может и не иметь.
+
Прямой связи между АК и АТД нет. АТД может быть абстрактным
 +
классом, а может и не быть. Аналогично, АК может иметь
 +
инкапсулированную структуру, а может и не иметь.
=== Абстрактный класс ===
=== Абстрактный класс ===
-
;В объектно-ориентированных языках программирования абстрактный класс реализуются следующими тремя способами
+
;В объектно-ориент. яп абстрактный класс реализуются следующими тремя способами
: 1. Модификатор abstract перед классом. Используется в C# и Java.
: 1. Модификатор abstract перед классом. Используется в C# и Java.
-
: 2. Класс содержит хотя бы один абстрактный метод. В C# и Java абстрактный метод обозначается модификатором abstract перед объявлением метода. В C++ абстрактные методы называются чистыми виртуальными. Примеры:
+
: 2. Класс содержит хотя бы один абстрактный метод. В C# и Java абстрактный метод обозначается модификатором abstract перед объявлением метода. В C++ абстр. методы называются чистыми виртуальными. Например
-
// тело отсутствует
+
void Draw() = 0; // тело отсутствует
-
virtual void draw() = 0; // C++
+
: 3. Если в классе, производном от абстрактного класса с абстрактными методами, не замещен хотя бы один абстрактный метод, то класс тоже является абстрактным. В C# и Java незамещенные абстрактные методы должны быть явно объявлены как абстрактные. В языке C# абстрактными могут быть и свойства:
-
abstract void draw(); // Java, C#
+
-
: 3. Если в классе, производном от абстрактного класса с абстрактными методами, не замещен хотя бы один абстрактный метод, то класс тоже является абстрактным. В C# и Java незамещенные абстрактные методы должны быть явно объявлены как абстрактные.
+
-
В языке C# абстрактными могут быть и свойства:
 
abstract int Length { get;}
abstract int Length { get;}
- 
-
Пример абстрактного класса ('''Java''' или '''C#'''):
 
-
abstract class ShapesClass
 
-
{
 
-
abstract public int Area();
 
-
}
 
- 
-
Абстрактные методы (функции) есть в C++, Java, Delphi, C#, Ада 95.
 
- 
-
=== Абстрактный тип данных ===
 
- 
-
В большинстве языков абстрактный тип данных реализуется с помощью интерфейсов. См. пример в соответствующем разделе.
 
- 
-
В Ада используется ключевое слово '''limited:'''
 
-
type Stack is limited private;
 
-
В ОБЕРОН И ОБЕРОН-2 АТД позволяют открывать поля структуры.
 
- 
-
=== Пример абстрактного ТД и абстрактных функций в Ада95 ===
 
- 
-
Мы продемонстрируем абстрактные классы, описывая несколько реализаций одной и той же абстракции; абстрактный класс будет определять структуру данных Set, и производный класс — реализовывать множество в виде булевого массива. В языке Ada 95 слово abstract обозначает абстрактный тип и абстрактные подпрограммы, связанные с этим типом:
 
- 
-
'''package''' Set_Package '''is '''
 
-
'''type''' Set '''is abstract tagged null record''';
 
-
'''function''' Union(S1, S2: Set) '''return''' Set '''is abstract''';
 
-
'''function''' Intersection(S1, S2: Set) '''return''' Set '''is abstract''';
 
-
'''end''' Set_Package;
 
- 
-
Вы не можете объявить объект абстрактного типа и не можете вызвать абстрактную подпрограмму. Тип служит только каркасом для порождения конкретных типов, а подпрограммы должны замещаться конкретными подпрограммами.
 
- 
-
Рассмотрим производный тип, в котором множество представлено булевым массивом:
 
- 
-
'''with''' Set_Package;
 
-
'''package''' Bit_Set_Package '''is'''
 
-
'''type''' Set '''is new''' Set_Package.Set '''with private''';
 
-
'''function''' Union(S1, S2: Set) '''return''' Set;
 
-
'''function''' lntersection(S1, S2: Set) '''return''' Set;
 
-
'''private'''
 
-
'''type''' Bit_Array is '''array'''(1..100) '''of''' Boolean;
 
-
'''type''' Set '''is new''' Set_Package.Set '''with'''
 
-
'''record'''
 
-
Data: Bit_Array;
 
-
'''end record''';
 
-
'''end''' Bit_Set_Package;
 
- 
-
Конечно, необходимо тело пакета, чтобы реализовать операции.
 
=== Интерфейс ===
=== Интерфейс ===
-
Интерфейс состоит только из абстрактных методов. В нем нет реализации методов (как нет и невиртуальных методов), нет нестатических полей (статические поля, например константы, допустимы).
+
Интерфейс состоит только из абстрактных методов. В нем нет реализации методов (как нет и не виртуальных методов), нет нестатических членов (статические члены, например константы, допустимы).
-
Пример моделирования интерфейса на C++:
+
Пример на C++:
-
class Set {
+
class Set{
public:
public:
virtual void Incl(T & x) = 0
virtual void Incl(T & x) = 0
Строка 1578: Строка 808:
virtual ~Set () {} // деструктор
virtual ~Set () {} // деструктор
};
};
- 
-
==== Явная и неявная реализация интерфейса ====
 
- 
-
Явная реализация интерфейса означает, что вызов метода
 
-
интерфейса может происходить только через ссылку на интерфейс, но не
 
-
может происходить через ссылку на класс, реализующий интерфейс. Перед
 
-
вызовом интерфейсного метода необходимо явно преобразовать ссылку на
 
-
объект реализующего класса к ссылке на интерфейс. Концепция явной
 
-
реализации полезна, например, при конфликте имен между унаследованными
 
-
интерфейсами. Используется только в С#.
 
-
Явная реализация всегда статична, неявная же может быть виртуальной.
 
-
Неявная реализация может быть абстрактной и реализовываться только в
 
-
классе-потомке. Явная реализация не может быть абстрактной, но
 
-
сам класс может иметь другие абстрактные методы и сам быть абстрактным.
 
- 
-
interface ISomeInterface
 
-
{
 
-
void F();
 
-
}
 
-
class CoClass: ISomeInterface
 
-
{
 
-
void ISomeInterface.F() { //в случае неявного интерфейса, здесь стояло бы public void F() {
 
-
System.Console.WriteLine(“Явно реализованный метод”);
 
-
}
 
-
// ...
 
-
}
 
-
// ...
 
-
CoClass c = new CoClass();
 
-
 
-
c.F(); // ошибка: нельзя вызывать явно реализованный метод
 
-
// интерфейса через ссылку на объект
 
-
 
-
((ISomeInterface)c).F(); // все нормально
 
== Множественное наследование ==
== Множественное наследование ==
-
Полностью реализовано только в C++. В Ada, C#, Delphi, Java множественное наследование поддерживается только для интерфейсов<ref>По крайней мере в контексте Java более корректно будет говорить не о наследовании ('''extends'''), а реализации ('''implements''') или частичной реализации интерфейса (последнее возможно только для абстрактных классов)</ref>.
+
Полностью реализовано только в C++. В Ada, C#, Delphi, Java множественное наследование поддерживается только для интерфейсов.
== Динамическая идентификация типа ==
== Динамическая идентификация типа ==
Строка 1664: Строка 861:
В Java тип объекта может быть получен при помощи метода getClass(), объявленного в классе java.lang.Object и потому реализуемого каждым классом. Для проверки принадлежности объекта определенному типу используется оператор instanceof (obj instanceof SomeClass), он заменяет dynamic_cast из C++. Также принадлежность объекта классу может быть определена с помощью оператора приведения типа, который в случае несоответствия типов выбрасывает исключение ClassCastException.
В Java тип объекта может быть получен при помощи метода getClass(), объявленного в классе java.lang.Object и потому реализуемого каждым классом. Для проверки принадлежности объекта определенному типу используется оператор instanceof (obj instanceof SomeClass), он заменяет dynamic_cast из C++. Также принадлежность объекта классу может быть определена с помощью оператора приведения типа, который в случае несоответствия типов выбрасывает исключение ClassCastException.
- 
-
=== ADA ===
 
-
В Аде для определения типа существует ключевое слово '''in''' работающее аналогично '''is''' в, скажем, Oberon-2.
 
-
После этого можно приводить типы, пользуясь мощным механизм конвертирования Ады (в аде вместо понятия приведения типов/type casting используется понятие конвертирование типов/type conversion):
 
-
Derived_Object: Derived := Derived (Base_Object) ''-- Здесь будет производится проверка в run-time''
 
== Понятие о родовых объектах. Обобщенное программирование ==
== Понятие о родовых объектах. Обобщенное программирование ==
=== ADA ===
=== ADA ===
-
Note to C++ programmers: generic units are similar to C++ templates.
+
Note to C++ programmers: generic units are similar to C++ templates. [http://www.example.com Ada Programming]
Объявляем шаблон:
Объявляем шаблон:
Строка 1694: Строка 886:
'''type''' Multiplable_T '''is''' '''private'''; ''-- Generic formal type parameter''
'''type''' Multiplable_T '''is''' '''private'''; ''-- Generic formal type parameter''
'''with''' '''function''' "*" ( X, Y: Multiplable_T) '''return''' Multiplable_T;
'''with''' '''function''' "*" ( X, Y: Multiplable_T) '''return''' Multiplable_T;
-
 
+
== ==
:Оператор loop определяет повторное выполнение последовательности операторов.
:Оператор loop определяет повторное выполнение последовательности операторов.
:Операторы with выполняют последовательность операторов в зависимости от результата проверки типа и применяют охрану типа к каждому вхождению проверяемой переменной внутри этой последовательности операторов.
:Операторы with выполняют последовательность операторов в зависимости от результата проверки типа и применяют охрану типа к каждому вхождению проверяемой переменной внутри этой последовательности операторов.
- 
-
=== C# ===
 
-
В C# используется конструкция where для определения
 
-
ограничений на параметры родовых (другое название - обобщенных)
 
-
конструкций.
 
-
Ее вид: where имя_типа : список_ограничений.
 
-
;Виды ограничений
 
-
: интерфейс — означает, что параметр-тип должен реализовывать этот интерфейс;
 
- 
-
: имя класса (может быть только одно такое ограничение в списке) означает, что параметр-тип должен быть наследником этого класса;
 
- 
-
: struct или class – означает, что параметр-тип должен быть структурой или классом;
 
- 
-
: new() - означает, что параметр-тип должен иметь конструктор умолчания (без параметров).
 
- 
-
Пример универсального шаблона (generic), реализующего односвязный список.
 
-
// type parameter T in angle brackets
 
-
public class GenericList<T>
 
-
{
 
-
// The nested class is also generic on T.
 
-
private class Node
 
-
{
 
-
// T used in non-generic constructor.
 
-
public Node(T t)
 
-
{
 
-
next = null;
 
-
data = t;
 
-
}
 
-
private Node next;
 
-
public Node Next
 
-
{
 
-
get { return next; }
 
-
set { next = value; }
 
-
}
 
-
// T as private member data type.
 
-
private T data;
 
-
// T as return type of property.
 
-
public T Data
 
-
{
 
-
get { return data; }
 
-
set { data = value; }
 
-
}
 
-
}
 
-
private Node head;
 
-
// constructor
 
-
public GenericList()
 
-
{
 
-
head = null;
 
-
}
 
-
// T as method parameter type:
 
-
public void AddHead(T t)
 
-
{
 
-
Node n = new Node(t);
 
-
n.Next = head;
 
-
head = n;
 
-
}
 
-
public IEnumerator<T> GetEnumerator()
 
-
{
 
-
Node current = head;
 
-
while (current != null)
 
-
{
 
-
yield return current.Data;
 
-
current = current.Next;
 
-
}
 
-
}
 
-
}
 
- 
-
== Параллельное программирование ==
 
- 
-
=== ADA ===
 
-
Ада реализует концепцию так называемых задач ('''task'''), что по сути является синонимом потока. Задача оформляется совершенно аналогично модулю, но может быть объявлена и описана где угодно, даже в теле подпрограммы:
 
- 
-
'''package''' Tasked '''is'''
 
-
'''procedure''' Tasked_proc '''is'''
 
-
'''task''' Untyped_task_1 '''is'''
 
-
''Some declarations'' ''-- Здесь объявляем все так, как будто объявляем пакет''
 
-
'''end''' task;
 
-
'''task''' Untyped_task_2; ''-- Мы можем ничего и не открывать в задаче внешнему миру''
 
-
''-- Мы можем объявлять как отдельные задачи''
 
-
'''task''' '''type''' Task_Type '''is''' ''-- Так и целые типы задач''
 
-
''Some declarations''
 
-
'''end''' Task_Type;
 
-
 
-
Typed_task_1, Typed_task_2 : Task_Type; ''-- Две одинаковые задачи''
 
-
 
-
'''task''' '''body''' Untyped_task_1 '''is''' '''separate'''; ''-- Можно описать задачу отдельно''
 
-
'''task''' '''body''' Untyped_task_2 '''is'''
 
-
'''something''' '''is''' '''separate'''; ''-- Или часть задачи отдельно''
 
-
'''begin'''
 
-
'''...''' ''-- Собственно то, что будет делать задача''
 
-
'''end''';
 
-
'''end''' Untyped_task_2;
 
-
 
-
'''task''' '''body''' Task_Type '''is'''
 
-
'''...''' ''-- Тело типа задачи''
 
-
'''end''' Task_Type;
 
-
 
-
''-- Тут начинают работать наши 4 задачи параллельно: Untyped_task_1, Untyped_task_2, Typed_task_1, Typed_task_2''
 
-
''-- На самом деле их 5, так как главный процесс рассматривается как неявная задача''
 
-
'''begin''' ''-- Tasked_proc''
 
-
Do_Something;
 
-
'''...'''
 
-
''-- Здесь задача, запустившая потомков будет ожидать их завершения''
 
-
'''end''' Tasked_proc;
 
-
'''end''' Tasked;
 
- 
-
В Аде есть множество методов синхронизации задач. Рассмотрим один из них - ''entry''. Это что-то на подобии точек входа в задачу извне. По своему объявлению, это - самые обычные процедуры, однако описываются и работают они по-другому. Когда одна задача хочет запросить у другой какую-либо услугу, она вызывает '''entry''', которая реализовывает данную услугу. В теле задачи (непосредственно в выполняемом коде), реализующей услугу есть участки кода, описывающих тела '''entry'''. Описание начинается со слова '''accept''' . Задача, вызвавшая '''entry''' будет ожидать, когда задача, реализующая этот '''entry''' дойдет до его тела. Этот момент называется '''Rendezvou''' (рандеву, свидание). Если несколько задач, одновременно (это слово, естественно, не стоит воспринимать буквально) вызвали '''entry''', то они становятся в очередь (тут уже речь идет, наверное, о названии Orgy хD ). Как это все выглядит:
 
- 
-
'''task''' '''type''' Service ''is''
 
-
'''type''' Some_Type '''is''' '''range''' -10 .. 10;
 
-
'''entry''' Plus ( X: '''in''' Some_Type );
 
-
'''entry''' Minus ( X: '''in''' Some_Type );
 
-
'''entry''' Get ( X: '''out''' Some_Type ); ''-- Повторюсь, entry - те же процедуры у которых могут быть in/out параметры.''
 
-
'''end''' Service;
 
- 
-
Кроме того для того чтобы задача не простаивала, тела '''accept''' можно объединить в блок '''select''', который будет выбирать запрошенные entry,
 
- 
-
'''task''' '''body''' Service ''is''
 
-
Some_Var: Some_Type;
 
-
'''begin'''
 
-
Some_Var := 0;
 
-
'''loop'''
 
-
 
-
'''accept''' Get ( X: '''out''' Some_Type ) '''do''' ''-- Здесь будем простаивать, пока кто-нибудь не запросит Get;
 
-
X := Some_Var;
 
-
'''end''' Get;
 
-
 
-
'''select''' ''-- Здесь либо сразу выполняем одно из запрошенных (Plus, Minus), либо ждем, пока придет запрос на один из этих '''entity''' ''
 
-
'''accept''' Plus ( X: '''in''' Some_Type ) '''do'''
 
-
Some_Var := Some_Var + X;
 
-
'''end''' Plus;
 
-
'''or'''
 
-
'''accept''' Minus ( X: '''in''' Some_Type ) '''do'''
 
-
Some_Var := Some_Var - X;
 
-
'''end''' Minus;
 
-
'''end select''';
 
-
'''end loop''';
 
-
'''end''' Service;
 
- 
-
В этом примере, естественно лучше было все 3 '''accept''' запихнуть в '''select''' - было бы меньше простоев, но для примера я оставил так.
 
- 
-
=== Modula-2 ===
 
- 
-
В языке Modula-2 есть низкоуровневый механизм ''сопрограмм''.
 
- 
-
Отличия сопрограммы от процесса:
 
-
# Известно, что сопрограммы выполняются квазипараллельно. Следовательно, их использование исключает трудную проблему взаимодействия истинно параллельных процессов.
 
-
# Переключение процессора от одной сопрограммы к другой осществляется явным ''оператором передачи управления''. Выполнение сопрограммы, которой передаётся управление, возобновляется с той точки, где она была приостановлена последним таким оператором.
 
== Примеры кода ==
== Примеры кода ==
Строка 1861: Строка 905:
m_j = m_i * 4;
m_j = m_i * 4;
}
}
-
public static void main(String[] args)
+
public static void main(String [] argv)
{
{
final int N = 5; // final — аналог констант в языках C/C++
final int N = 5; // final — аналог констант в языках C/C++
Строка 1892: Строка 936:
for (double y[] : b) {
for (double y[] : b) {
if (x.length != y.length) {
if (x.length != y.length) {
-
break label2; // прервать внешний цикл
+
break label2; // аналог goto
}
}
}
}
Строка 2200: Строка 1244:
Pink Lady - fruit
Pink Lady - fruit
Pink Lady - apple
Pink Lady - apple
- 
-
=== Примеры на C++, Ада и Java с использованием шаблонов ===
 
- 
-
Стек:
 
- 
-
GENERIC
 
-
TYPE T IS PRIVATE; SIZE : INTEGER;
 
-
PACKAGE Stacks IS
 
-
TYPE Stack IS LIMITED PRIVATE;
 
-
PROCEDURE Push(S: IN OUT Stack; X : IN T);
 
-
PROCEDURE Pop(S: IN OUT Stack; X : OUT T);
 
-
FUNCTION IsEmpty(S : IN Stack) RETURN BOOLEAN;
 
-
FUNCTION IsFull(S : IN Stack) RETURN BOOLEAN;
 
-
PRIVATE
 
-
TYPE Stack is RECORD
 
-
Body : ARRAY (1..SIZE) OF T;
 
-
Top : INTEGER := 1;
 
-
END RECORD;
 
-
END Stacks;
 
- 
-
template <typename T, int size> class Stack
 
-
{
 
-
public:
 
-
Stack() {top = 0;}
 
-
void Push(T x);
 
-
T Pop(T& x);
 
-
bool IsEmpty();
 
-
bool IsFull();
 
-
private:
 
-
Stack (const Stack& s);
 
-
T body[N];
 
-
int top;
 
-
};
 
-
Очередь:
 
- 
-
generic
 
-
type T is private;
 
-
Size : integer;
 
-
package G_Queue is
 
-
type Queue is limited private;
 
-
procedure Enqueue(Q: inout Queue; X:T);
 
-
procedure Dequeue(Q: inout Queue; X:T);
 
-
procedure Init(Q: out Queue);
 
-
procedure Destroy(Q: inout Queue);
 
-
function IsFull(Q: Queue);
 
-
function IsEmpty(Q: Queue);
 
-
–- другие процедуры ...
 
-
private
 
-
type Queue is record
 
-
Left, Right: integer;
 
-
body : array(1..Size) of T;
 
-
end record;
 
-
end G_Queue;
 
- 
-
Дек:
 
- 
-
generic
 
-
type T is private;
 
-
package G_Deque is
 
-
type Deque is limited private;
 
-
procedure PushRight(Deq: inout Deque; X:T);
 
-
procedure PushLeft(Deq: inout Deque; X:T);
 
-
procedure PopRight(Deq: inout Deque; X: out T);
 
-
procedure PopLeft(Deq: inout Deque; X: out T);
 
-
procedure Init(Deq: out Deque);
 
-
procedure Destroy(Deq: inout Deque);
 
-
function IsFull(Deq: Deque);
 
-
function IsEmpty(Deq: Deque);
 
-
–- другие процедуры ...
 
-
private
 
-
type PLink is access;
 
-
type Link is record inf : T; next, prev : PLink; end record;
 
-
type PLink is access Link;
 
-
type Deque is record Left, Right: PLink; end record;
 
-
end G_Deque;
 
- 
-
interface IDeque<T>
 
-
{
 
-
void PushLeft(T x);
 
-
void PushRight(T x);
 
-
T PopLeft();
 
-
T PopRight();
 
-
bool IsFull();
 
-
bool IsEmpty();
 
-
// другие функции
 
-
}
 
- 
-
Функция перемножения матриц:
 
- 
-
template <class T> Matrix<T>& MatMult (Matrix<T>& A, Matrix<T>& B);
 
-
 
-
Matrix<float> b,c;
 
-
// конкретизация функции
 
-
Matrix<float> a = MatMult(b,c);
 
- 
-
generic
 
-
type T is private;
 
-
with function “+”(x,y:T) return T (<>);
 
-
with function “*”(x,y:T) return T (<>);
 
-
type Matrix is private;
 
-
function G_MatMult(A,B: Matrix) return Matrix;
 
- 
-
=== Примеры кода на С# ===
 
-
Пример обработки исключений в '''C#.'''
 
-
 
-
class NegativeValueException : Exception
 
-
{
 
-
public NegativeValueException(string message) : base(message)
 
-
{
 
-
}
 
-
}
 
-
// ...
 
-
string path = @"c:\users\public\test.txt";
 
-
var file = new System.IO.StreamReader(path);
 
-
try
 
-
{
 
-
var buffer = file.ReadLine();
 
-
var time = Int32.Parse(buffer);
 
-
if ( time < 0)
 
-
{
 
-
throw new NegativeValueException("Time must be a positive value.");
 
-
}
 
-
MyClassInstance.Foo(time);
 
-
}
 
-
catch (System.IO.IOException e)
 
-
{
 
-
Console.WriteLine("Error reading from {0}. Message = {1}", path, e.Message);
 
-
}
 
-
catch (NegativeValueException e)
 
-
{
 
-
Console.WriteLine("Value error. Message = {0}", e.Message);
 
-
}
 
-
catch (Exception e)
 
-
{
 
-
if (e is ArgumentNullException || e is FormatException || e is OverflowException)
 
-
{
 
-
Console.WriteLine("Parsing error. Message = {0}", e.Message);
 
-
}
 
-
else
 
-
{
 
-
Console.WriteLine("Oops, something went wrong. Message = {0}", e.Message);
 
-
}
 
-
}
 
-
finally
 
-
{
 
-
if (file != null)
 
-
{
 
-
file.Close();
 
-
}
 
-
}
 
- 
-
Ключевое слово ''event'' в '''C#''' позволяет уменьшить объём кода, необходимого для реализации событийной модели взаимодействия на делегатах. Иначе говоря, это такой синтаксический сахар для упрощения работы с обратными вызовами.
 
- 
-
using System;
 
-
namespace wildert
 
-
{
 
-
public class Metronome
 
-
{
 
-
public event TickHandler Tick; // объявляем событие Tick
 
-
public EventArgs e = null;
 
-
public delegate void TickHandler(Metronome m, EventArgs e);
 
-
public void Start()
 
-
{
 
-
while (true)
 
-
{
 
-
System.Threading.Thread.Sleep(3000);
 
-
if (Tick != null)
 
-
{
 
-
Tick(this, e); // генерируем событие Tick
 
-
}
 
-
}
 
-
}
 
-
}
 
-
public class Listener
 
-
{
 
-
public void Subscribe(Metronome m)
 
-
{
 
-
// регистрируем обработчик события Tick
 
-
m.Tick += new Metronome.TickHandler(HeardIt);
 
-
}
 
-
private void HeardIt(Metronome m, EventArgs e)
 
-
{
 
-
System.Console.WriteLine("HEARD IT");
 
-
}
 
-
 
-
}
 
-
class Test
 
-
{
 
-
static void Main()
 
-
{
 
-
Metronome m = new Metronome();
 
-
Listener l = new Listener();
 
-
l.Subscribe(m);
 
-
m.Start();
 
-
}
 
-
}
 
-
}
 
- 
-
; Замечание
 
-
: Делегат — это тип, который определяет сигнатуру метода. При создании экземпляра делегата можно связать этот экземпляр с любым методом с совместимой сигнатурой. Метод можно запустить (или вызвать) с помощью экземпляра делегата. Делегаты похожи на указатели на функции в C++.<ref>Процитировано из [http://msdn.microsoft.com/ru-ru/library/ms173171.aspx msdn].</ref>
 
- 
-
=== Моделирование приватных типов данных из Ады в C++ ===
 
- 
-
''-- ADA ''
 
-
 
-
''-- head''
 
-
'''package''' P '''is'''
 
-
'''type''' T '''is''' '''limited private''';
 
-
'''function''' Convert (X: in T) '''return''' Integer;
 
-
'''end''' P;
 
-
 
-
''-- body''
 
-
'''package''' '''body''' P '''is'''
 
-
'''type''' T '''is record'''
 
-
'''...'''
 
-
'''end record''';
 
-
'''function''' Convert (X: in T) '''return''' Integer '''is'''
 
-
'''...'''
 
-
'''end''' Convert;
 
-
'''end''' P;
 
- 
-
'' //C++''
 
-
 
-
'' //P.hpp''
 
-
'''class''' P {
 
-
'''public:'''
 
-
P();
 
-
'''operator''' int () const;
 
-
'''private:'''
 
-
P(const P&);
 
-
'''...'''
 
-
}
 
- 
-
=== Эмуляция в Java private и limited private из Ады ===
 
-
В Java нет перегрузки операций, поэтому эмуляция limited невозможна на Java. Эмуляция private реализуется таким же способом, что сверху:
 
- 
-
''//P.java''
 
-
'''class''' P {
 
-
'''public''' P() {
 
-
'''...'''
 
-
}
 
-
'''public''' int convert () {
 
-
'''...'''
 
-
}
 
-
'''private ...'''
 
-
}
 
== Итоговая таблица ==
== Итоговая таблица ==
Строка 2464: Строка 1262:
!Ada95
!Ada95
|-
|-
-
!Оператор перехода «goto метка»
+
!есть оператор перехода «goto метка»
|есть
|есть
|есть
|есть
|есть
|есть
-
|нет<ref>Есть break '''label'''; и continue '''label''';, где '''label''' ставится с двоеточием перед началом цикла и указывает, какой именно цикл (в случае continue — итерацию какого именно цикла) среди тех, в которые вложен данный оператор, нужно прервать. В Java есть зарезервированное слово goto, но оно не несёт никаких функций — оператора безусловного перехода в языке нет (однако переход осуществить можно, см. [http://www.docjar.com/docs/api/com/sun/org/apache/bcel/internal/generic/GOTO.html]).</ref>
+
|нет<ref>Есть break ''label'', где ''label'' ставится с двоеточием перед началом цикла.</ref>
|есть
|есть
|есть
|есть
Строка 2477: Строка 1275:
|есть
|есть
|-
|-
-
!Конструкция "свойство" (property)
+
!есть конструкция "свойство" (property)
|нет
|нет
|нет
|нет
Строка 2490: Строка 1288:
|нет
|нет
|-
|-
-
!Абстрактные методы
+
!есть абстрактные функции
|нет
|нет
|есть
|есть
Строка 2503: Строка 1301:
|есть
|есть
|-
|-
-
!Виртуальные методы (a.k.a. динамическое связывание методов)
+
!есть перегрузка (overloading)
-
|нет<ref>Обычно реализуется через указатели на функции и указатели на структуры с указателями на функции.</ref>
+
-
|есть
+
-
|есть
+
-
|есть
+
-
|нет
+
-
|есть
+
-
|нет
+
-
|есть
+
-
|нет<ref>Комитет ISO утвердил т.н. &laquo;объектное расширение&raquo; (OO extension). (См.: стандартизация [http://sc22wg13.twi.tudelft.nl ISO Modula-2].) В получившемся языке каждый метод виртуален (взято [http://computer-programming-forum.com/27-modula2/2a715a4b1cce6ba6.htm отсюда]). Однако в канонической Modula-2 даже наследования-то нет (собственно, это одна из фич Oberon).</ref>
+
-
|нет
+
-
|есть
+
-
|-
+
-
!Перегрузка (overloading)
+
-
|нет
+
-
|есть
+
-
|есть
+
-
|есть
+
-
|нет
+
-
|есть
+
-
|нет
+
-
|нет
+
-
|нет
+
-
|есть
+
-
|есть
+
-
|-
+
-
!Исключения (exceptions)<ref>Исключения также есть и в Visual Basic.</ref>
+
|нет
|нет
|есть
|есть
Строка 2542: Строка 1314:
|есть
|есть
|-
|-
-
!Конструкция try-finally
+
!есть try-finally
|нет<ref>Имитируется макросами через <tt>goto cleanup;</tt></ref>
|нет<ref>Имитируется макросами через <tt>goto cleanup;</tt></ref>
|нет<ref>Декларируется отстутвие необходимости ввиду налиия RAII; есть в качестве расширения в некоторых реализациях (GCC, MSVC)</ref>
|нет<ref>Декларируется отстутвие необходимости ввиду налиия RAII; есть в качестве расширения в некоторых реализациях (GCC, MSVC)</ref>
Строка 2555: Строка 1327:
|нет
|нет
|-
|-
-
!Раздельная независимая трансляция
+
!есть понятие связывания подпрограмм (методов класса) на этапе выполнения (динамического связывания)
 +
|нет<ref>Обычно реализуется через указатели на функции и указатели на структуры с указателями на функции.</ref>
 +
|есть
|есть
|есть
|есть
|есть
|нет
|нет
 +
|есть
|нет
|нет
-
|нет
+
|есть
-
|есть<ref>С версии 4.0.</ref>
+
-
|нет
+
-
|нет
+
-
|нет
+
|нет
|нет
|нет
|нет
 +
|есть
|-
|-
-
!Тип запись (struct, record)
+
!Тип Запись (struct, record)
|есть
|есть
-
|есть<ref>Является классом с публичной областью видимости для полей; если не использовать виртуальные методы, близок по использованию к структурам в C.</ref>
+
|есть<ref>Является классом с публичной областью видимости для полчей; если не использовать виртуальные етоды, близок по использованию к структурам в C</ref>
|есть
|есть
|нет
|нет
Строка 2581: Строка 1353:
|есть
|есть
|-
|-
-
!Размеченные объединения
+
!Оператор loop
-
|ч/и<ref>Обычный '''union''' + детерминант + ручная проверка</ref>
+
|
-
|и<ref>Или как в С, или используя [http://www.boost.org/doc/libs/1_52_0/doc/html/variant.html boost::variant]</ref>
+
|
-
|нет
+
|
-
|нет
+
|
 +
|
 +
|
|есть
|есть
|есть
|есть
-
|нет
 
-
|нет<ref>Нет в Оберон; учитывая характер изменений, внесённых в Оберон-2, делаем вывод о том, что размеченных объединений в нём нет. </ref>
 
-
|есть
 
-
|есть<ref name="yes-for-ada-implementation">Есть в Ада; вероятно, есть и в конкретной реализации.</ref>
 
-
|есть<ref name="yes-for-ada-implementation" />
 
-
|-
 
-
!Перечисления
 
-
|есть
 
-
|есть
 
-
|есть
 
-
|есть
 
-
|есть
 
-
|есть
 
-
|нет
 
-
|нет
 
|есть
|есть
|есть
|есть
|есть
|есть
|-
|-
-
!Запрещение замещения метода в произвольных классах или наследования класса
+
!Оператор with
-
|нет
+
-
|нет
+
-
|есть<ref>Используется ключевое слово '''sealed'''.</ref>
+
-
|есть<ref>Используется ключевое слово '''final'''.</ref>
+
-
|нет
+
|нет
|нет
|нет
|нет
|нет
|нет
|нет
|нет
 +
|есть
 +
|есть
|нет
|нет
 +
|есть
 +
|есть
 +
|нет<ref>Ключевое слово '''with''' означает импортирование классов в текущую область видимости.</ref>
|нет
|нет
|-
|-
Строка 2645: Строка 1404:
|есть
|есть
|есть
|есть
-
|-
 
-
!Вложенные модули
 
-
|нет
 
-
|есть<ref>См. статью [http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2073.pdf «Модули в С++»].</ref>
 
-
|есть
 
-
|нет (?)
 
-
|нет<ref name="no-nested-modules-pascal">Вложенными могут быть только подпрограммы, которые не являются библиотечными модулями.</ref>
 
-
|нет<ref name="no-nested-modules-pascal" />
 
-
|нет<ref name="no-nested-modules-pascal" />
 
-
|нет<ref name="no-nested-modules-pascal" />
 
-
|есть
 
-
|есть
 
-
|есть
 
-
 
|-
|-
!АТД
!АТД
Строка 2665: Строка 1410:
|есть
|есть
|есть
|есть
-
|нет
+
|
|есть
|есть
|есть
|есть
|есть
|есть
|ч/и<ref>Делаем структуру, скрыто экспортируем указатель на неё в другой модуль.</ref>
|ч/и<ref>Делаем структуру, скрыто экспортируем указатель на неё в другой модуль.</ref>
-
|есть<ref name="ada-ADT">См. статью [http://www.cs.auckland.ac.nz/~jmor159/PLDS210/ada_adt.html «Абстрактные типы данных в Ada»].</ref>
+
|
-
|есть<ref name="ada-ADT" />
+
|
|-
|-
!Расширяющее программирование
!Расширяющее программирование
Строка 2678: Строка 1423:
-
|нет
+
|
|есть
|есть
Строка 2691: Строка 1436:
|есть
|есть
|есть
|есть
-
|нет
+
|
|есть
|есть
Строка 2704: Строка 1449:
-
|нет<ref>Стандарт Паскаля — не поддерживает! [[w:Компонентный Паскаль]] и далее — поддерживают.</ref>
+
|
Строка 2717: Строка 1462:
|нет
|нет
|нет
|нет
-
|нет
+
|
|нет
|нет
|ч/и
|ч/и
Строка 2740: Строка 1485:
!Параллельное программирование
!Параллельное программирование
|нет
|нет
-
|нет<ref>В C++11 появился std::thread. [http://en.cppreference.com/w/cpp/thread/thread Подробнее].</ref>
+
|нет<ref>В C++10 появился std::thread. [http://en.cppreference.com/w/cpp/thread/thread Подробнее].</ref>
|есть
|есть
|есть
|есть
-
|нет
+
|
|нет
|нет
|нет
|нет
|нет
|нет
|ч/и?
|ч/и?
-
|есть
+
|
-
|есть
+
|
|-
|-
-
!Рефлексивное программирование
+
!Рефлективное программирование
|нет
|нет
|есть
|есть
-
|нет
+
|
-
|нет
+
|
-
|нет
+
|
-
|нет
+
|
-
|-
+
-
!Передача параметров по значению
+
-
|есть
+
-
|есть
+
-
|есть<ref>cм. [http://msdn.microsoft.com/en-us/library/0f66670z(v=vs.71).aspx#vclrfpassingmethodparameters_valuetypes MSDN].</ref>
+
-
|есть
+
-
|есть
+
-
|есть
+
-
|есть
+
-
|есть
+
-
|есть
+
-
|есть<ref name="keyword_in">Ключевое слово in (подразумевается по умолчанию).</ref>
+
-
|есть<ref name="keyword_in" />
+
-
|-
+
-
!Передача параметров по ссылке
+
-
|и<ref>Моделируется с помощью указателей.</ref>
+
-
+
-
|есть<ref>Модификаторы '''ref''' и '''out''', также см. [http://msdn.microsoft.com/en-us/library/0f66670z(v=vs.71).aspx#vclrfpassingmethodparameters_referencetypes MSDN].</ref>
+
-
+
-
|есть<ref name="keyword_var">Ключевое слово var.</ref>
+
-
|есть<ref name="keyword_var" />
+
-
|есть<ref name="keyword_var" />
+
-
|есть<ref name="keyword_var" />
+
-
|есть<ref name="keyword_var" />
+
-
|есть<ref name="keyword_access">Ключевое слово access.</ref>
+
-
|есть<ref name="keyword_access" />
+
|}
|}
:ч/и - частично имитируется
:ч/и - частично имитируется

Пожалуйста, обратите внимание, что все ваши добавления могут быть отредактированы или удалены другими участниками. Если вы не хотите, чтобы кто-либо изменял ваши тексты, не помещайте их сюда.
Вы также подтверждаете, что являетесь автором вносимых дополнений, или скопировали их из источника, допускающего свободное распространение и изменение своего содержимого (см. eSyr's_wiki:Авторское право).
НЕ РАЗМЕЩАЙТЕ БЕЗ РАЗРЕШЕНИЯ ОХРАНЯЕМЫЕ АВТОРСКИМ ПРАВОМ МАТЕРИАЛЫ!

Шаблоны, использованные на этой странице:

Личные инструменты
Разделы