Главная страница
Навигация по странице:

  • ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ

  • Объектноориентированное программирование


    Скачать 1.73 Mb.
    НазваниеОбъектноориентированное программирование
    Дата21.11.2018
    Размер1.73 Mb.
    Формат файлаpdf
    Имя файлаOOP-PrePrint.pdf
    ТипКонспект
    #57177
    страница1 из 15
      1   2   3   4   5   6   7   8   9   ...   15


    Министерство образования и науки Российской Федерации
    Южно-Уральский государственный университет
    Кафедра системного программирования
    004.4(07)
    Р159
    Г.И. Радченко, Е.А. Захаров
    ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ
    ПРОГРАММИРОВАНИЕ
    Конспект лекций
    Челябинск
    Издательский центр ЮУрГУ
    2013

    УДК 004.4(075.8)
    Р159
    Одобрено
    учебно-методической комиссией
    факультета вычислительной математики и информатики.
    Конспект лекций подготовлен в соответствии с ФГОС ВПО 3-го поколе-
    ния по образовательным направлениям 010300.62 «Фундаментальная ин-
    форматика и информационные технологии» и 010400.62 «Прикладная ма-
    тематика и информатика».
    Рецензенты:
    доктор физ.-мат. наук, профессор В.И. Ухоботов,
    кандидат технических наук А.В. Созыкин
    Р159
    Радченко, Г.И.
    Объектно-ориентированное программирование / Г.И. Рад- ченко, Е.А. Захаров.

    Челябинск: Издательский центр ЮУрГУ,
    2013.

    167 с.
    В учебном пособии представлены основы применения объектно- ориентированного программирования. Рассмотрены основные концеп- ции объектно-ориентированного программирования на примере языка программирования С++. Рассматриваются понятия класса и объекта, концепция наследования, шаблоны функций и классов, методы пере- грузки операторов, методы обработки исключительных ситуаций. При- водится обзор основных порождающих, структурных и поведенческих паттернов проектирования. Рассматриваются особенности использова- ния стандартной библиотеки шаблонов (STL) в С++.
    Пособие предназначено для студентов бакалавриата по направле- нию 010300 «Фундаментальная информатика и информационные тех- нологии» при изучении курса «Объектно-ориентированное програми- рование», а также для обучения студентов бакалавриата по направле- нию 010400 «Прикладная математика и информатика».
    УДК 004.4(075.8)
    © Издательский центр ЮУрГУ, 2013

    3
    1.
    ВВЕДЕНИЕ
    1.1
    Сложность разработки программного обеспечения
    Мы окружены сложными системами:

    персональный компьютер;

    любое дерево, цветок, животное;

    любая материя – от атома до звезд и галактик;

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

    сложностью реальной предметной области, из которой исходит заказ на разработку;

    трудностью управления проектированием;

    необходимостью обеспечить достаточную гибкость программы;

    сложность описания поведения больших дискретных систем.
    1.2
    Декомпозиция
    Декомпозиция

    один из способов борьбы со сложностью.
    Рис. 1. Пример алгоритмической декомпозиции

    4
    Необходимо разделять систему на независимые подсистемы, каждую из которых разрабатывать отдельно. Выделяют следующие методы декомпо- зиции:

    алгоритмическая декомпозиция (см. рис. 1);

    объектно-ориентированная декомпозиция (см. рис. 2).
    1.3
    Краткая история языков программирования
    Выделяют следующие этапы развития языков программирования высо- кого уровня:

    Языки первого поколения (1954

    1958)

    FORTRAN 1
    Математические формулы

    ALGOL-58
    Математические формулы

    Языки второго поколения (1959

    1961)

    FORTRAN II Подпрограммы

    ALGOL-60
    Блочная структура, типы данных

    COBOL
    Описание данных, работа с файлами

    LISP
    Обработка списков, указатели, сборка мусора

    Языки третьего поколения (1962

    1970)

    PL/I
    FORTRAN+ALGOL+COBOL

    Pascal
    Простой наследник ALGOL-60

    Simula
    Классы, абстракция данных

    Разрыв преемственности (1970

    1980)
    Рис. 2. Пример объектно-ориентированной декомпозиции

    5

    C
    Эффективный высокоуровневый язык

    FORTRAN 77 Блочная структура, типы данных

    Бум ООП (1980

    1990)

    Smalltalk 80
    Чисто объектно-ориентированный язык

    C++
    С + Simula

    Ada83
    Строгая типизация; сильное влияние Pascal

    Появление инфраструктур (1990

    …)

    Java
    Блочная структура, типы данных

    Python
    Объектно-ориентированный язык сценариев

    Visual C#
    Конкурент языка Java для среды Microsoft .NET
    1-е поколение (рис. 3) преимущественно использовалось для научных и технических вычислений, математический словарь. Языки освобождали от сложностей ассемблера, что позволяло отступать от технических деталей реализации компьютеров.
    Программы, написанные на языках программирования первого поколе- ния, имеют относительно простую структуру, состоящую только из глобаль- ных данных и подпрограмм.
    Языки 2-го поколения (рис. 4) сделали акцент на алгоритмических аб- стракциях, что приблизило разработчиков к предметной области. Появилась процедурная абстракция, которая позволила описать абстрактные про- граммные функции в виде подпрограмм.
    На 3-е поколение языков программирования (рис. 5) влияние оказало то, что стоимость аппаратного обеспечения резко упала, при этом, производи- тельность экспоненциально росла. Языки поддерживали абстракцию дан- ных и появилась возможность описывать свои собственные типы данных
    Рис. 3. Топология языков первого поколения

    6
    (структуры). В 1970-е годы было создано несколько тысяч языков програм- мирования для решения конкретных задач, но практически все из них ис- чезли. Осталось только несколько известных сейчас языков, которые про- шли проверку временем.
    В модули собирали подпрограммы, которые будут изменяться сов- местно, но их не рассматривали как новую технику абстракции.
    В 1980-е произошел бум развития объектно-ориентированного програм- мирования (рис. 6). Языки данного времени лучше всего поддерживают объ- ектно-ориентированную декомпозицию ПО. В 90-х появились инфраструк- туры (J2EE, .NET), предоставляющие огромные объемы интегрированных сервисов.
    Рис. 4. Топология языков второго поколения
    Рис. 5. Топология языков третьего поколения

    7
    Основным элементом конструкции служит модуль, составленный из ло- гически связанных классов и объектов, а не подпрограмма.
    1.4
    Объектно-ориентированное программирование
    Объектно-ориентированное программирование – это методология про- граммирования, основанная на представлении программы в виде совокуп- ности объектов, каждый из которых является экземпляром определенного класса, а классы образуют иерархию наследования.
    Объект – это нечто, имеющее четко определенные границы. Однако, этого недостаточно, чтобы отделить один объект от другого или дать оценку качества абстракции. Объект обладает состоянием, поведением и идентич- ностью; структура и поведение схожих объектов определяет общий для них класс; термины «экземпляр класса» и «объект» взаимозаменяемы.
    Класс – это множество объектов, обладающих общей структурой, пове- дением и семантикой. Отдельный объект – это экземпляр класса. Класс представляет лишь абстракцию существенных свойств объекта.
    Состояние объекта характеризуется перечнем (обычно статическим) всех свойств данного объекта и текущими (обычно динамическими) значе- ниями каждого из этих свойств. Например: торговый автомат имеет свой-
    Рис. 6. Топология объектно-ориентированного программирования

    8 ство: способность принимать монеты; этому свойству соответствует дина- мическое значение – количество принятых монет. Пример описания состо- яния объекта: struct PersonnelRecord { char name[100]; int socialSecurityNumber; char department[10]; float salary;
    };
    Поведение объекта – это то, как объект действует и реагирует; поведение выражается в терминах состояния объекта и передачи сообщений. Опера- цией называется определенное воздействие одного объекта на другой с це- лью вызвать соответствующую реакцию. Например, клиент может активи- зировать операции append()
    и pop()
    для того, чтобы управлять объектом- очередью: class Queue { public:
    Queue();
    Queue(const Queue&); virtual

    Queue(); virtual Queue& operator=(const Queue&); virtual int operator==(const Queue&) const; int operator!=(const Queue&) const; virtual void clear(); virtual void append(const void*); virtual void remove(int at); virtual int length() const; virtual int isEmpty() const;
    };
    Индивидуальность объекта – это такое свойство объекта, которое отли- чает его от всех других объектов. В большинстве языков программирования при создании объект именуется, поэтому многие путают адресуемость и ин- дивидуальность. Невозможность отличить имя объекта от самого объекта является источником множества ошибок в ООП.

    9
    2.
    ОБЪЕКТНО
    -
    ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ
    .
    ЯЗЫК С++
    Объектно-ориентированное программирование строится на трех осново- полагающих принципах: инкапсуляция, полиморфизм и наследование.
    2.1
    Инкапсуляция
    Инкапсуляция – это процесс отделения друг от друга элементов объекта, определяющих его устройство и поведение; инкапсуляция служит для того, чтобы изолировать контрактные обязательства абстракции от их реализа- ции.
    Пусть члену класса требуется защита от «несанкционированного до- ступа». Как разумно ограничить множество функций, которым такой член будет доступен? Очевидный ответ для языков, поддерживающих объектно- ориентированное программирование, таков: доступ имеют все операции, которые определены для этого объекта, иными словами, все функции- члены. Например: class window
    {
    // ... protected:
    Rectangle inside;
    // ...
    }; class dumb_terminal: public window
    {
    // ... public: void prompt();
    // ...
    };
    Здесь в базовом классе window член inside типа
    Rectangle описыва- ется как защищенный (
    protected
    ), но функции-члены производных клас- сов, например, dumb_terminal::prompt()
    , могут обратиться к нему и вы- яснить, с какого вида окном они работают. Для всех других функций член window::inside недоступен.
    В таком подходе сочетается высокая степень защищенности с гибко- стью, необходимой для программ, которые создают классы и используют их.

    10
    Неочевидное следствие из этого: нельзя составить полный и окончатель- ный список всех функций, которым будет доступен защищенный член, по- скольку всегда можно добавить еще одну, определив ее как функцию-член в новом производном классе. Для метода абстракции данных такой подход часто бывает мало приемлемым. Если язык ориентируется на метод абстрак- ции данных, то очевидное для него решение – это требование указывать в описании класса список всех функций, которым нужен доступ к члену. В
    С++ для этой цели используется описание частных (
    private
    ) членов.
    Важность инкапсуляции, т.е. заключения членов в защитную оболочку, резко возрастает с ростом размеров программы и увеличивающимся разбро- сом областей приложения.
    2.2
    Наследование
    Наследование представляет собой способность производить новый класс из существующего базового класса. Производный класс – это новый класс, а базовый класс – существующий класс. Когда вы порождаете один класс из другого (базового класса), производный класс наследует элементы базового класса. Для порождения класса из базового начинайте определение произ- водного класса ключевым словом class
    , за которым следует имя класса, двоеточие и имя базового класса, например class dalmatian: dog
    Когда вы порождаете класс из базового класса, производный класс мо- жет обращаться к общим элементам базового класса, как будто эти эле- менты определены внутри самого производного класса. Для доступа к част- ным данным базового класса производный класс должен использовать ин- терфейсные функции базового класса.
    Внутри конструктора производного класса ваша программа должна вы- звать конструктор базового класса, указывая двоеточие, имя конструктора базового класса и соответствующие параметры сразу же после заголовка конструктора производного класса.
    Чтобы обеспечить производным классам прямой доступ к определенным элементам базового класса, в то же время защищая эти элементы от остав- шейся части программы, C++ обеспечивает защищенные (
    protected
    ) эле- менты класса. Производный класс может обращаться к защищенным эле- ментам базового класса, как будто они являются общими. Однако для остав- шейся части программы защищенные элементы эквивалентны частным.
    Если в производном и базовом классе есть элементы с одинаковым име- нем, то внутри функций производного класса C++ будет использовать эле-

    11 менты производного класса. Если функциям производного класса необхо- димо обратиться к элементу базового класса, вы должны использовать опе- ратор глобального разрешения, например base class:: member
    2.3
    Полиморфизм
    Полиморфный объект представляет собой такой объект, который может изменять форму во время выполнения программы.
    В объектно-ориентированных языках класс является абстрактным типом данных. Полиморфизм реализуется с помощью наследования классов и вир- туальных функций. Класс-потомок наследует сигнатуры методов класса-ро- дителя, а реализация, в результате переопределения метода, этих методов может быть другой, соответствующей специфике класса-потомка. Другие функции могут работать с объектом класса-родителя, но при этом вместо него во время исполнения будет подставляться один из классов-потомков.
    Это называется поздним связыванием.
    Класс-потомок сам может быть родителем. Это позволяет строить слож- ные схемы наследования – древовидные или сетевидные.
    Абстрактные (или чисто виртуальные) методы не имеют реализации во- обще. Они специально предназначены для наследования. Их реализация должна быть определена в классах-потомках.
    Класс может наследовать функциональность от нескольких классов. Это называется множественным наследованием. Множественное наследование создаёт проблему (когда класс наследуется от нескольких классов-посред- ников, которые в свою очередь наследуются от одного класса (так называе- мая «Проблема ромба»): если метод общего предка был переопределён в по- средниках, неизвестно, какую реализацию метода должен наследовать об- щий потомок. Решается эта проблема через виртуальное наследование.
    2.4
    История появления C++
    В 1980 году Бьерн Страуструп в AT&T Bell Labs стал разрабатывать рас- ширение языка С под условным названием C++. Стиль ведения разработки вполне соответствовал духу, в котором создавался и сам язык С, – в него вводились те или иные возможности с целью сделать более удобной работу конкретных людей и групп. Первый коммерческий транслятор нового языка, получившего название C++ появился в 1983 году. Он представлял со- бой препроцессор, транслировавший программу в код на С. Однако факти-

    12 ческим рождением языка можно считать выход в 1985 году книги Стра- уструпа. Именно с этого момента C++ начинает набирать всемирную попу- лярность.
    Главное нововведение C++

    механизм классов, дающий возможность определять и использовать новые типы данных. Программист описывает внутреннее представление объекта класса и набор функций-методов для до- ступа к этому представлению. Одной из заветных целей при создании C++ было стремление увеличить процент повторного использования уже напи- санного кода. Концепция классов предлагала для этого механизм наследо- вания. Наследование позволяет создавать новые (производные) классы с расширенным представлением и модифицированными методами, не затра- гивая при этом скомпилированный код исходных (базовых) классов. Вместе с тем наследование обеспечивает один из механизмов реализации полимор- физма базовой концепции объектно-ориентированного программирования, согласно которой, для выполнения однотипной обработки разных типов данных может использоваться один и тот же код. Собственно, полиморфизм тоже один из методов обеспечения повторного использования кода.
    Введение классов не исчерпывает всех новаций языка C++. В нем реали- зованы полноценный механизм структурной обработки исключений, отсут- ствие которого в С значительно затрудняло написание надежных программ, механизм шаблонов – изощренный механизм макрогенерации, глубоко встроенный в язык, открывающий еще один путь к повторной используемо- сти кода, и многое другое.
    Таким образом, генеральная линия развития языка была направлена на расширение его возможностей путем введения новых высокоуровневых конструкций при сохранении сколь возможно полной совместимости с
    ANSI С. Конечно, борьба за повышение уровня языка шла и на втором фронте: те же классы позволяют при грамотном подходе упрятывать низко- уровневые операции, так что программист фактически перестает непосред- ственно работать с памятью и системно-зависимыми сущностями.
    На данный момент существуют следующие стандарты языка С++:

    ANSI C++ / ISO-C++ – 1996 год,

    ISO/IEC 14882:1998 – 1998 год,

    ISO/IEC 14882:2003 – 2003 год,

    C++/CLI – 2005 год,

    TR1 – 2005 год,

    C++11 – 2011 год.

    13
    2.5
    Нововведения и отличия C++ от C
    В C++ появились классы и объекты. Технически, класс C++ – это тип структуры в C, а объект – переменная такого типа. Разница только в том, что в C++ есть еще модификаторы доступа и полями могут быть не только дан- ные, но и функции (функции-методы).
    В C++ появились две новые операции: new и delete
    . В первую очередь это – сокращения для распространенных вызовов функций malloc и free
    :
    При вызове new автоматически вызывается конструктор, а при вызове delete
    – деструктор. Так что нововведение можно описать формулой: new
    = malloc
    + конструктор, delete
    = free
    + деструктор.
    В C++ появились функции, которые вызываются автоматически после создания переменной структуры (конструкторы) и перед ее уничтожением
    (деструкторы). Во всех остальных отношениях это – обычные функции, на которые наложен ряд ограничений. Некоторые из этих ограничений ничем не оправданы и мешают: например, конструктор нельзя вызвать напрямую
    (деструктор, к счастью, можно). Нельзя вернуть из конструктора или де- структора значение. Что особенно неприятно для конструктора. А деструк- тору нельзя задать параметры.
    При программировании на C часто бывает так, что имеется несколько вариантов одной и той же структуры, для которых есть аналогичные функ- ции. Например, есть структура, описывающая точку (
    Point
    ) и структура, описывающая окружность (
    Circle
    ). Для них обоих часто приходится вы- полнять операцию рисования (
    Point
    ). Так что, если у нас есть блок данных, где перемешаны точки, окружности и прочие графические примитивы, то перед нами стоит задача быстро вызвать для каждого из них свою функцию рисования.
    Обычное решение – построить таблицу соответствия «вариант струк- туры – функция». Затем берется очередной примитив, определяется его тип, и по таблице вызывается нужная функция. В C++ всем этим занимается ком- пилятор: достаточно обозначить функцию-метод как virtual
    , и для всех одноименных функций будет создана таблица и поле типа, за которыми сле- дить будет также компилятор. При попытке вызвать функцию с таким име- нем, будет вызвана одна из серии одноименных функций в зависимости от типа структуры.
    Исключение по своей сути – это последовательность goto и return
    . Ос- новано на C-технологии setjmp
    /
    longjmp try и catch
    – это setjmp с про- веркой. throw
    – это longjmp
    . Когда вызывается throw
    , то проверяется: если

    14 он окажется внутри блока try
    , то выполняется goto на парный блок catch
    Если нет, то делается return и ищется catch на уровень выше и так далее.
      1   2   3   4   5   6   7   8   9   ...   15


    написать администратору сайта