Основы объектно-ориентированного программирования



         

Assembler - язык неограниченных возможностей

Говорят, что ассемблер трудно выучить. Любой язык программирования трудно выучить. Легко выучить С или Delphi после Паскаля, потому что они похожи. А попробуйте освоить Lisp, Forth или Prolog, и окажется, что ассемблер в действительности даже проще, чем любой совершенно незнакомый язык программирования.
Говорят, что программы на ассемблере трудно понять. Разумеется, на ассемблере легко написать неудобочитаемую программу... точно так же, как и на любом другом языке! Если вы знаете язык и если автор программы не старался ее запутать, то понять программу будет не сложнее, чем если бы она была написана на Бейсике.

Введение
Первый вопрос, который задает себе человек, впервые услышавший об этом языке программирования, а зачем он, собственно, нужен? Особенно теперь, когда все пишут на C/C++, Delphi или других языках высокого уровня? Ведь очень многое можно создать на С, но ни один язык, даже такой популярный, не может претендовать на то, чтобы на нем можно было написать действительно все.

Что потребуется для работы с ассемблером
Прежде всего вам потребуется ассемблер. Здесь самое время сказать, что на самом деле язык программирования, которым мы собираемся заниматься, называется язык ассемблера (assembly language). Ассемблер это программа, которая переводит текст с языка, понятного человеку, в язык, понятный процессору, то есть говорят, что она переводит язык ассемблера в машинный код. Однако сначала в повседневной речи, а затем и в литературе слово ассемблер стало также и названием самого языка программирования.

Представление данных в компьютерах
Двоичная система счисления
Биты, байты и слова
Биты, байты и слова - 2
Шестнадцатеричная система счисления
Числа со знаком
Логические операции
Коды символов

Процессоры Intel в реальном режиме
Процессор Intelx86 после включения питания оказывается в так называемом режиме реальной адресации памяти, или просто реальном режиме. Большинство операционных систем сразу же переводят его в защищенный режим, позволяющий им обеспечивать многозадачность, распределение памяти и другие функции. Пользовательские программы в таких операционных системах часто работают еще в одном режиме, режиме V86, из которого им доступно все то же, что и из реального, кроме команд, относящихся к управлению защищенным режимом.

Регистры процессора
Регистры общего назначения
Сегментные регистры
Стек
Регистр флагов
Способы адресации
Регистровая адресация
Непосредственная адресация
Прямая адресация
Косвенная адресация

Директивы и операторы ассемблера
Каждая программа на языке ассемблера помимо команд процессора содержит еще и специальные инструкции, указывающие самому ассемблеру, как организовывать различные секции программы, где располагаются данные, а где команды, позволяющие создавать макроопределения, выбирать тип используемого процессора, организовывать связи между процедурами и т.д. К сожалению, пока нет единого стандарта на эти команды

Структура программы
Структура программы - 2
Псевдокоманды определения переменных
Структуры
Сегменты
Сегменты - 2
Модели памяти и определение сегментов
Модели памяти и определение сегментов - 2
Порядок загрузки сегментов
Процедуры

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

Программа типа СОМ
Программа типа СОМ - 2
Программа типа ЕХЕ
Средства DOS
Средства DOS - 2
Средства BIOS
Средства BIOS - 2
Средства BIOS - 3
Средства BIOS - 4
Прямая работа с видеопамятью

Более сложные приемы программирования
Все примеры программ из предыдущей главы в первую очередь предназначались для демонстрации работы с теми или иными основными устройствами компьютера при помощи средств, предоставляемых DOS и BIOS. В этой главе рассказано о том, что и в области собственно программирования ассемблер позволяет больше, чем любой другой язык, и рассмотрены те задачи, решая которые, принято использовать язык ассемблера при программировании для DOS.

Структуры IF.. THEN... ELSE
Структуры CASE
Конечные автоматы
Циклы
Процедуры и функции
Передача параметров
Передача параметров по значению
Передача параметров по ссылке
Передача параметров по возвращаемому
Передача параметров по результату

Блочные устройства
Для всех остальных команд в поле буфера запроса со смещением +1 размещается номер логического устройства из числа обслуживаемых драйвером, к которому относится команда: 01h:Проверка носителя

Программирование в защищенном режиме
Все, о чем рассказано до этой главы, рассчитано на работу под управлением DOS в реальном режиме процессора (или в режиме V86), унаследованном еще с семидесятых годов. В этом режиме процессор неспособен адресоваться к памяти выше границы первого мегабайта. Кроме того, из-за того, что для адресации используются 16-битные смещения, невозможно работать с массивами больше 65536 байт.

Адресация в защищенном режиме
Адресация в защищенном режиме - 2
Адресация в защищенном режиме - 3
Адресация в защищенном режиме - 4
Интерфейс VCPI
Интерфейс VCPI - 2
Интерфейс VCPI - 3
Интерфейс DPMI
Переключение в защищенный режим
Функции DPMI управления дескрипторами

Программирование для Windows 95 и Windows NT
Несмотря на то что Windows95 и WindowsNT кажутся более сложными операционными системам по сравнению с DOS, программировать для них на ассемблере намного проще. С одной стороны, Windows-приложение запускается в 32-битном режиме (мы не рассматриваем Windows3.11 и более старые версии, которые работали в 16-битном режиме) с моделью памяти flat, так что программист получает все те преимущества, о которых говорилось в предыдущей главе, а с другой стороны нам больше не нужно изучать в деталях, как программировать различные устройства компьютера на низком уровне.

Первая программа
Первая программа - 2
Первая программа - 3
Консольные приложения
Консольные приложения - 2
Консольные приложения - 3
Консольные приложения - 4
Окно типа MessageBox
Окна
Окна - 2

Ассемблер и языки высокого уровня
В предыдущем разделе, занимаясь программированием для Windows, мы уже обращались к процедурам, написанным на языке высокого уровня из программ на ассемблере, и создавали процедуры на ассемблере, к которым можно обращаться из языков высокого уровня. Для этого нужно было соблюдать определенные договоренности о передаче параметров параметры помещались в стек справа налево, результат возвращался в ЕАХ, стек освобождался от переданных параметров самой процедурой. Эта договоренность, известная как STDCALL, конечно, не единственная, и разные языки высокого уровня используют разнообразные способы передачи параметров.

Передача параметров
Конвенция Pascal
Конвенция С
Смешанные конвенции
Искажение имен
Встроенный ассемблер
Встроенный ассемблер в Pascal
Встроенный ассемблер в С

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

Высокоуровневая оптимизация
Оптимизация на среднем уровне
Вычисление констант вне цикла
Перенос проверки условия в конец цикла
Выполнение цикла задом наперед
Разворачивание циклов
Общие принципы низкоуровневой оптимизации
Основные рекомендации
Команда LEA
Выравнивание

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

Регистры
Системные флаги
Регистры управления памятью
Регистры управления процессором
Регистры управления процессором - 2
Отладочные регистры
Отладочные регистры - 2
Машинно-специфичные регистры
Системные и привилегированные команды
Системные и привилегированные команды - 2

Программирование на ассемблере в среде UNIX
Операционная система MS-DOS, получившая дальнейшее развитие в виде Windows, долгое время была практически единственной операционной системой для персональных компьютеров на базе процессоров Intel. Но с течением времени мощность процессоров выросла настолько, что для них стало возможным работать под управлением операционных систем класса UNIX, использовавшихся обычно на более мощных компьютерах других компаний. В настоящее время существует более двадцати операционных систем для Intel, представляющих те или иные диалекты UNIX. Мы рассмотрим наиболее популярные из них.

Синтаксис AT&T
Основные правила
Запись команд
Адресация
Операторы ассемблера
Префиксные, или унарные операторы
Инфиксные, или бинарные операторы
Директивы ассемблера
Директивы определения данных
Директивы управления символами

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

Символы ASCII
Номера строк соответствуют первой цифре в шестнадцатеричном коде символа, номера столбцов второй, так что, например, код большой латинской буквы A 41h

Управляющие символы ASCII
Кодировки второй половины ASCII
Коды символов расширенного ASCII
Скан-коды клавиатуры
Команды INTEL 80x86
Общий формат команды процессора Intel
Значения полей кода команды
Значения поля ModRM
Значения поля SIB
Общая информация о скоростях выполнения

Основы объектно-ориентированного программирования

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

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

Обзор внешних факторов
Корректность (Correctness)
Устойчивость (Robustness)
Расширяемость (Extendibility)
Повторное использование (Reusability)
Совместимость (Compatibility)
Эффективность (Efficiency)
Эффективность (Efficiency) - 2
Эффективность (Efficiency) - 3
Переносимость (Portability)

О критериях
Рассмотрим выбор критериев, позволяющих оценить объектную ориентированность системы (objectness).

До какой степени мы догматичными?
Категории
Метод и язык
Бесшовность (seamlessness)
Классы
Утверждения (Assertions)
Классы как модули
Классы как типы
Вычисления, основанные на компонентах
Скрытие информации (information hiding)

Пять критериев
Метод проектирования, который можно называть "модульным", должен удовлетворять пяти основным требованиям: Декомпозиции (decomposability). Композиции (composability). Понятности (understandability). Непрерывности (continuity). Защищенности (protection).

Декомпозиция
Декомпозиция - 2
Модульная Композиция
Модульная Композиция - 2
Модульная Понятность
Модульная Непрерывность
Модульная Непрерывность - 2
Модульная Защищенность
Пять правил
Прямое отображение

Цели повторного использования
Прежде всего, следует понять, почему так важно улучшать возможности повторного использования ПО. Здесь незачем обращаться к доводам типа "любовь к матери и яблочному пирогу". Как мы увидим, наша борьба за повторное использование преследует надлежащие цели, позволит избежать миражей, и принесет хороший доход от соответствующих инвестиций.

Ожидаемые преимущества
Ожидаемые преимущества - 2
Потребители повторно используемых программ
Что следует повторно использовать?
Повторное использование персонала
Повторное использование проектов
Образцы проектов (design patterns)
Образцы проектов (design patterns) - 2
Повторное использование исходного текста
Повторное использование абстрактных модулей

Ингредиенты вычисления
При поиске правильной архитектуры ПО критическим является вопрос о модуляризации: какие критерии нужно использовать при выделении модулей наших программ? Чтобы верно ответить на него, нужно сравнить соперничающих кандидатов.

Базисный треугольник
Базисный треугольник - 2
Функциональная декомпозиция
Непрерывность
Проектирование сверху вниз
Проектирование сверху вниз - 2
Не только одна главная функция
Не только одна главная функция - 2
Обнаружение вершины
Функции и эволюция

Различные реализации
Надо сказать, что стеки присутствуют в дидактических представлениях абстрактных типов данных в таком большом количестве, что Э. Дейкстра как-то остроумно заметил, что "абстрактные типы данных являются прекрасной теорией, целью которой является описание стеков". Совершенно справедливо. Но в следующих лекциях курса понятие абстрактных типов данных так часто применяется в гораздо более сложных случаях, что я не чувствую стыда, начиная рассмотрение с этого ключевого примера. Он является простейшим из известных мне примеров, содержащих в себе почти все важные идеи абстрактных типов данных.

Представления стеков
Представления стеков - 2
Опасность излишней спецификации
Какова длина второго имени?
К абстрактному взгляду на объекты
Использование операций
Политика невмешательства в обществе модулей
Согласованность имен
Можно ли обойтись без абстракций?
Можно ли обойтись без абстракций? - 2

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

Устранение традиционной путаницы
Роль классов
Модули и типы
Класс как модуль и как тип
Унифицированная система типов
Унифицированная система типов - 2
Простой класс
Компоненты
Атрибуты и подпрограммы
Атрибуты и подпрограммы - 2

Объекты
В процессе выполнения ОО-система создает некоторое число объектов. Организация этих объектов и отношения между ними определяют конструкцию времени выполнения. Рассмотрим свойства объектов.

Что такое объект?
Базовая форма
Простые поля
Простое представление книги - класс BOOK
Писатели
Ссылки
Ссылки - 2
Идентичность объектов
Объявление ссылок
Ссылка на себя

Что происходит с объектами
ОО-программа создает объекты. Предыдущая лекция показала, как полезно полагаться на динамическое создание для получения гибких объектных структур, подстраивающихся автоматически к нуждам системы.

Создание объектов
Создание объектов - 2
Использование динамического режима
Повторное использование памяти в трех режимах
Отсоединение
Недостижимые объекты
Достижимые объекты в классическом подходе
Достижимые объекты в классическом подходе - 2
Достижимые объекты в ОО-модели
Проблема управления памятью в ОО-модели

Горизонтальное и вертикальное обобщение типа
Уже изученные механизмы позволяют написать класс, помещенный в центр рисунка - LIST_OF_BOOKS, экземпляр которого представляет список книг. У класса следующие компоненты: put для вставки элемента, remove для удаления элемента, count для подсчета числа элементов и т.д. Очевидны два пути обобщения понятия LIST_OF_BOOKS.

Необходимость параметризованных классов
Родовые АТД
Проблема
Роль типизации
Родовые классы
Объявление родового класса
Использование родового класса
Терминология
Проверка типов
Правило типизации

Базисные механизмы надежности
Технические приемы, введенные в предыдущих лекциях, были направлены на создание надежного ПО. Дадим их краткий обзор - было бы бесполезно рассматривать более продвинутые концепции до приведения в порядок основных механизмов надежности. Первым и определяющим свойством объектной технологии является почти навязываемая структура программной системы - простая, модульная, расширяемая, - проще гарантирующая надежность, чем в случае "кривых" структур, возникающих при применении ранних методов разработки. В частности, усилия по ограничению межмодульного взаимодействия, сведения его к минимуму, были в центре дискуссии о модульности. Результатом стал запрет общих рисков, снижающих надежность, - отказ от глобальных переменных, механизм ограниченного взаимодействия модулей, отношения наследования и вложенности.

О корректности ПО
О корректности ПО - 2
Выражение спецификаций
Формула корректности
Сильные и слабые условия
Сильные и слабые условия - 2
Введение утверждений в программные тексты
Предусловия и постусловия
Класс стек
Предусловия

Базисные концепции обработки исключений
Литература по обработке исключений зачастую не очень точно определяет, что вызывает исключение. Как следствие, механизм исключений, представленный в таких языках программирования как PL/I и Ada, часто неправильно используется: вместо того, чтобы резервироваться только для истинно чрезвычайных ситуаций, они заканчивают службу как внутрипрограммные инструкции goto, нарушающие принцип Защищенности.

Отказы
Исключения
Источники исключений
Ситуации отказа
Обработка исключений
Как не следует делать это - C-Unix пример
Как не следует делать это - Ada пример
Как не следует делать это - Ada пример - 2
Принципы обработки исключений
Принципы обработки исключений - 2

Взаимодействие с не объектным ПО
До сих пор, элементы ПО выражались полностью в ОО-нотации. Но программы появились задолго до распространения ОО-технологии. Часто возникает необходимость соединить объектное ПО с элементами, написанными, например, на языках С, Fortran или Pascal. Нотация должна поддерживать этот процесс.

Внешние программы
Улучшенные варианты
Использование внешних программ
ОО-изменение архитектуры (re-architecturing)
ОО-изменение архитектуры (re-architecturing) - 2
Гибридный продукт или гибридные языки?
Передача аргументов
Передача аргументов - 2
Инструкции
Вызов процедуры

Многоугольники и прямоугольники
Для объяснения основных понятий рассмотрим простой пример. Здесь приведен скорее набросок этого примера, а не полный его вариант, но он хорошо показывает все существенные идеи.

Многоугольники
Многоугольники - 2
Прямоугольники
Прямоугольники - 2
Основные соглашения и терминология
Наследование инварианта
Наследование и конструкторы
Пример иерархии
Полиморфизм
Полиморфное присоединение

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

Пример, неподходящий для введения
Может ли самолет быть имуществом?
Числовые и сравнимые значения
Окна - это деревья и прямоугольники
Деревья - это списки и их элементы
Составные фигуры
Составные фигуры - 2
Брак по расчету
Брак по расчету - 2
Структурное наследование

Наследование и утверждения
Обладая изрядной мощью, наследование может быть и опасным. Не будь механизма утверждений, создатели классов могли бы весьма "вероломно" пользоваться повторными объявлениями и динамическим связыванием для изменения семантики операций без возможности контроля со стороны клиента. Утверждения способны на большее: они дают нам боле глубокое понимание природы наследования. Не будет преувеличением сказать, что лишь понимание принципов Проектирования по Контракту позволяет в полной мере постичь сущность концепции наследования.

Инварианты
Предусловия при динамическом связывании
Предусловия при динамическом связывании - 2
Как обмануть клиентов
Как быть честным
Пример
Пример - 2
Устранение посредника
Субподряды
Абстрактные предусловия

Проблема типизации
О типизации при ОО-разработке можно сказать одно: эта задача проста в своей постановке, но решить ее подчас нелегко.

Базисная конструкция
Статическая и динамическая типизация
Правила типизации
Реализм
Пессимизм
Статическая типизация: как и почему
Преимущества
Преимущества - 2
Аргументы в пользу динамической типизации
Типизация: слагаемые успеха

Константы базовых типов
Правило стиля - принцип символических констант - гласит, что обращение к конкретному значению (числу, символу или строке) почти всегда должно быть косвенным. Должно существовать определение константы, задающее имя, играющее роль символической константы (symbolic constant), и связанное с ним значение - константа, называемаю манифестной (manifest constant). Далее в алгоритме следует использовать символическую константу. Тому есть два объяснения.

Атрибуты-константы
Использование констант
Константы пользовательских классов
Константы с манифестом для этого непригодны
Однократные функции
Применение однократных подпрограмм
Разделяемые объекты
Однократные функции с базовыми типами
Однократные процедуры
Параметры