лекции (2008) (by Михайлишин Алексей_ Жбанков Денис_ Щербинин Виктор_ Чеботарев Павел) (1160831), страница 8
Текст из файла (страница 8)
ввод-вывод обычно пишется в последнюю очередь, и готоваясистема выпускается поздно. Лучше, когда можно тестировать модули по мере их написания.Другой подход - top-down - наоборот. Реально используют комбинации первого и второго метода.Обозначение: O,M,D - Oberon, Modula, Delphi.Перегрузка операций - частный случай полиморфизма. Одному имени в одной и той же областивидимости соответствуют несколько семантик. Раньше в языках был жесткий принцип: каждому имени водном области видимости могла соотв. только одна семантика.
Но в современных языках только Оберон иМодула не имеют перегрузки функций. Во всех остальных она разрешена, и даже в двух формах статический полиморфизм и динамический полиморфизм.Оберон - единственный язык, в котором нет статического полиморфизма.// в ада:function P: boolean;function P: integer;if P then // по контексту можно определить тип//с++bool f();int f(); // нельзя, т.к. непонятно какой контекстЯвляются ли стандартные операции объектом перегрузки? В этом вопросе существует 2 течения:1) Ada, C#, C++ - разрешена перегрузка, стандартные операции считаются функциями +- можноперегружать в двух вариантах: двуместной и одноместной.
В прологе можно перегрузить +семиместным предикатом.2) Delphi, Java - перегружать стандартные операции нельзя.Для чего нужна перегрузка стандартных операций? Классический пример - матричная арифметика.package Matrix istype Matrix is ....function "+"(m1,m2: matrix)return Matrix;end Matrix;x, y, z: Matrix;z := x+y; // можноz := "+"(x,y) // тоже можноИспользовать такую форму можно только внутри пакета Matrix из-за области видимости.Другой пример:x,y,z: matrices.Matrix;z := "+"(x,y); // нельзя, т.к. компилятор не увидит такой операцииz := matrices."+"(x,y)Таким образом, все удобство перегрузки пропадает.
Необходимо иметь возможность "вбрасывать"видимость процедуры во внешнюю область.Возьмем для примера Модула-2. Сначала мы видим стандартные имена. Затем имена библиотечныхметодов, которые загружаются при выполнении import.PP1P12P2P21Если заполнять стек имен, находясь в определенном пространстве, то структура пространства можетстановиться очень сложной.IV) Инкапсуляция и абстрактные типы данныхВпервые понятие инкапсуляции появилось в 70х годах.Абстрактный тип данных – множество значений, структура которого полностью инкапсулирована.Наследование бессмысленно без динамического полиморфизма.
По мнению современных авторов, самымважным свойством современного языка программирования. является инкапсуляция. Инкапсуляция ="скрытие". В современном программировании очень важны интерфейсы, а хорошие интерфейсыневозможны без сокрытия некоторых свойств. Инкапсуляция "защищает" данные. С точки зренияинкапсуляции все объекты равны.Атомом защиты является либо тип целиком, либо часть типа (переменная, член класса и т.д.). В Адаатомом является тип, т.е. мы можем либо открыть весь тип, либо закрыть весь тип. Как следствие, нужновсе закрывать, т.е. программист должен использовать А.Т.Д.Оберон + языки с классами - атомами защиты служит часть типа.Модула-2:DEFINITION MODULE M;...CNDMIMPLEMENTATION MODULE M;...END MВ дельфи модуль также делится на 2 части - объявление и реализацию.
Ада - спецификация пакета. Все чтообъявлено в интерфейсе - видимо извне. Все что в реализации - закрыто, т.е. сама структура логическогомодуля основана на понятии инкапсуляции.TYPE LINK =RECORDEND // здесь реализована инкапсуляция; сам тип доступен извне, а его члены - нет(ини доступны только из того же модуля что и объявление)В общем случае АТД - это множество операций.М-2: АТД реализуется через скрытый тип данных. Он объявлен в модуле в таком виде:TYPE T;DEFINITION MODULE STACKS;TYPE STACK; // структура здесь скрыта и нам неизвестнаPROCEDURE INIT(var s: stack);PUSH(var s: stack);X:POP()...END STACKS;Над скрытым типом определены 2 операции - присваивание (:=) и сравнение (=, !=). Вирт не назвал типданных абстрактным, поскольку он не совсем абстрактен. Например, как действует семантика копированияприменительно к стеку? Возможны 2 семантики: "поверхностная" и "глубокая". В модула-2 - поверхностнаясемантика.
Скрытый ТД внутри реализации должен быть реализован либо в виде целого ТД либо в видеуказателя, поэтому он не является абстрактным в чистом виде.[lect22] Абстрактные типы данныхМодула-2 навязывает референциальную модель - реализация типа может быть только integer и pointer.Это связано с механизмом раздельной компиляции и принципом РОРИ (разделение, определение,реализация и использование).М-2, Ада, Дельфи, Паскаль - определение и реализация вынесены в разные модули. В Аде части пакетамогут быть помещены в разные файлы. Пусть в М-2 один модуль импортирует другой сервисный модуль,тогда компилятору для компиляции исходного модуля необходимо знать только определение модулясервиса.
В Аде если изменить спецификацию одного пакета, то все пакеты, использующие данный пакет,должны быть перетранслированы. В Дельфи (например, uses Service): что нужно сделать, чтобы вызватьперекомпиляцию модуля сервиса? В Си файлы .h это определение, а .cpp - интерфейс.
Если хедерменяется, то make перетранслирует весь проект.Иначе говоря, все языки 70-х годов поддерживают разделения объявлений и реализации.Скрытый тип только моделирует абстрактный тип, но не является им полностью. В М-2 есть двеконцепции: полный и ограниченный (полностью моделирует абстрактный) тип данных.Ада:package Stacks istype Stack is private;procedure Push (s: inout Stack; x: integer);procedure Pop (s: inout Stack; x: out integer);private //в ней нужно расписать реализацию абстрактного типаtype Stack in recordtop: integer := 0;foo: array (0..N) of integer;end record;end Stacks;Теперь можно написать Pop(s,x), но нельзя написать S.top := 1; поэтому тип является действительноприватным.type Stack is access;type Link is recordnext: Stack;x: integer;end record;type Stack is access Link;Операции сравнения и присваивания для составных типов определяются рекурсивно, так вот в Аде этиоперации применимы для типов с одинаковой длиной.
Копирование может быть поверхностным и глубоким(разница заметна, если в записи есть ссылки).type T is limited private; //ограниченный приватный тип данныхОберон - 1988:DEFINITION Stacks;TYPE Stack =RECORD...END;MODULE StacksTYPE Stack*=RECORD...END;Это тоже не совсем абстрактный тип данных, но с точки зрения гибкости этот тип даже превышаетаналогичный тип из Ада. Вирт отказался от принципа РОРИ. Сейчас в Java и C# есть средства,вытаскивающие из классов интерфейс.Глава 6. Определение новых типов данных с помощью классов.Класс - языковая конструкция, которая служит для объединения структуры данных и операций, ееобрабатывающих, в один набор. Основная роль класса - тип данных.
Класс похож на модуль. Стандартныеклассы маскируются подклассы ввиду удобства классов (например, Object, string).Collection - стандартный класс.Рассмотрим класс C++ Matrix.Операция A+B отличается от операции A+=B. В первом варианте возникает неоднозначность в случаеиспользования класса: какому классу принадлежит данная операция? А или В?Какому классу принадлежат функции exp и sin? В C# это класс Math, но он объявлен как закрытый инаследовать его нельзя, боле того нельзя порождать объекты этого класса. Таким образом, это не класс, этомодуль. Создатели C# придумали для него название "статический класс".I) Члены классовC++:class name : наследование{список членов класса;}Если нет наследования, то класс может быть верхом в иерархии.Delphi:type name = class (наследование)список членов классаend;Что насчет принципа РОРИ? Во время создания Delphi он был аксиомой.В языке C# есть понятие частичного класса (partial class).C++:class X{int i;void f (int j);};void X::f (int j){...}Delphi:type T = classprocedure P;end;procedure T.P;begin...end;Члены классов:• члены-данные• члены-функции• члены-типыЧлены-данные (и члены-функции):• статические• динамическиеСначала обсудим члены-данные.
Нестатические члены-данные - то же самое, что и поля в записи. Онидаже располагаются как поля. Некоторые реализации даже точно определяют порядок в памяти. В Дельфивсе члены нестатические. Статические члены - фактически глобальные переменные (C#, Java).Обращение:C++:Java, C#:X::i;X.i;[lect23] Члены классаstatic – модификатор для статических членов.Члены-данные.Обращение к статическому члену (С++): Class?name;В других языках вместо ? – точка.Обращение к нестатическим членам (С++): ObjectName.name;(В С++ также можно обращаться и к статическим членам, что не очень хорошо с точки зрения технологиипрограммирования)Распределение памяти.Для нестатических членов-данных – аналогично полям структур.Статические члены - в С# и Java –автоматически.В С++ нужно указывать, в каком конкретно модуле нужно отводить память под статический член-данных.Статические и нестатические члены-функции.Нестатическая член-функция – особая функция, отличающаяся от обычной в следующем:• Область действия – класс, в который она входит (в частности, она видна только из класса).• Неявный параметр – адрес объекта (C++, C#, Java – this (указатель), Delphi, Smalltalk, … – Self(ссылка)).Вызов: ObjectName.funcName(params)Возникает две области действия – класс и блок-тело функции-члена.
Вторая область видимости вложена впервую. Куда относятся формальные параметры метода? В Дельфи – они принадлежат области видимостикласса. В других языках (С++, …) они относятся к области видимости функции-члена.class X{int i;X(int i) { this>i=i; } //здесь можно без this, т.к. класс – область видимости.Это укорачивает код}Конфликта имен лучше избегать.Статические функции-члены:• Область действия – статические члены класса.В языке С++ статический член с точки зрения указателей похож на глобальную переменную (функцию)void (*pf)();void f();class X {public:int i, j;void f(); void g();static void f2();};pf=f; //можноpf=f2; //тоже можноС указателями на нестатические члены все подругому, т.к.