Механизм абстракции и повторного использования кода • • Абстра́кция да́нных — подход к обработке данных по принципу черного ящика. Данные обрабатываются функцией высокого уровня с помощью вызова функций низкого уровня. Обычно такой подход используется в объектноориентированном программировании, что позволяет работать с объектами, не вдаваясь в особенности их реализации. Повторное использование кода (code reuse) — методология проектирования компьютерных и других систем, заключающаяся в том, что система (компьютерная программа, программный модуль) частично либо полностью должна составляться из частей, написанных ранее компонентов и/или частей другой системы. Повторное использование — основная методология, которая применяется для сокращения трудозатрат при разработке сложных систем. Рассмотрим принцип абстрагирования Абстрагирование - процесс выделения абстракций в предметной области задачи. Абстракция - совокупность существенных характеристик некоторого объекта, которые отличают его от всех других видов объектов и, таким образом, четко определяют особенности данного объекта с точки зрения дальнейшего рассмотрения и анализа. Современный уровень абстракции предполагает объединение всех свойств абстракции (как касающихся состояния анализируемого объекта, так и определяющих его поведение) в единую программную единицу некий абстрактный тип (класс). Ограничение доступа - сокрытие отдельных элементов реализации абстракции, не затрагивающих существенных характеристик ее как целого. ! В языке C++ поддерживается два различных механизма абстракции: • объектно-ориентированный подход (Использование объектно-ориентированного подхода позволяет точно определить интерфейс и провести диспетчеризацию времени исполнения) • шаблоны (Шаблоны предназначены для более сложных интерфейсов и разрешены во время компиляции. В шаблонах отсутствует разделение между интерфейсами и реализацией) С++ предоставляет достаточно механизмов повторного использования кода… • Наследование • Дружественные функции, классы • Виртуальные функции • Абстрактные базовые классы • Перегруженные операторы • Итераторы • Перегрузка функций • Полиморфизм • Шаблонные функции, классы •… Затронем часть из них… • Наследование Наследование (inheritance) - это процесс, посредством которого один объект может приобретать свойства другого. Точнее, объект может наследовать основные свойства другого объекта и добавлять к ним черты, характерные только для него. Наследование является важным, поскольку оно позволяет поддерживать концепцию иерархии классов (hierarchical classification). Применение иерархии классов делает управляемыми большие потоки информации. Порождённый класс наследует все, связанные с родителем, качества и добавляет к ним свои собственные определяющие характеристики. Наследование играет очень важную роль в OOP. Форма определения: class Employee { /* описание класса-родителя */ }; class Manager : Employee { /* описание класса-потомка */ }; Пример, Класс-потомок наследует в частности конструктор базового: Категории членов класса Уровни наследования Public Protected Private Открытое Защищенное Закрытое наследование наследование наследование Открытые и Открытые и защищенные члены Открытые и защищенные члены базового класса защищенные члены базового класса остаются базового класса становятся соответственно, становятся защищенными членами открытыми и закрытыми членами производного класса защищенными членами производного класса производного класса. Во всех случаях члены базового класса остаются закрытыми и недоступными из производных классов Отношения между объектами классов «является» •Открытое наследование определят отношение «Является». •Все, что является истинным в отношении объектов класса Sphere, справедливо и для объектов класса Ball Если между классами нет отношения «является», открытое наследование применять не следует «содержит» Отношение «содержит», или включение, означает, что некий класс содержит в качестве члена объект другого класса. Таким образом, экземпляр класс Pen содержит внутри экземпляр класса Ball «подобен» В реализации класса Stack элементами стека можно манипулировать с помощью методов класса List Ни отношение «содержит», ни отношение «подобен» не допускает применения открытого наследования. Если классу нужен доступ к защищенным членам другого класса, либо есть необходимость переопределить функции данного класса, используется отношение «подобен», т.е. закрытое наследование. Дружественные функции Функции readSphereData и writeSphereData не являются членами класса Sphere. Они определяются вне класса Sphere. Эти функции имеют доступ к закрытому члену theRadius из класса Sphere. Дружественные классы Дружественный класс – это класс, являющийся другом другого. Объявляя некий класс другом класса С, мы открываем всем его функциям-членам доступ к закрытым и защищенным членам класс С. Класс List имеет привилегии доступа к item и text, которые принадлежат узлам, как если бы класс ListNode был простой структурой. Теперь конструктор класса List может инициализировать узлы списка (его можно предусмотреть и в самой структуре) Виртуальные функции Виртуальной называется функция, замещаемая в производном классе Абстрактный базовый класс В этом классе объявлены чисто виртуальные функции setRadius, getRadius и displayStatistics. Определим класс Sphere, используя EquidistShape в качестве базового класса • Полиморфизм Полиморфизм (polymorphism) (от греческого polymorphos) - это свойство, которое позволяет одно и то же имя использовать для решения двух или более схожих, но технически разных задач. Целью полиморфизма, применительно к объектноориентированному программированию, является использование одного имени для задания общих для класса действий. Выполнение каждого конкретного действия будет определяться типом данных. Например для языка Си, в котором полиморфизм поддерживается недостаточно, нахождение абсолютной величины числа требует трёх различных функций: abs(), labs() и fabs(). Эти функции подсчитывают и возвращают абсолютную величину целых, длинных целых и чисел с плавающей точкой соответственно. В С++ каждая из этих функций может быть названа abs(). Тип данных, который используется при вызове функции, определяет, какая конкретная версия функции действительно выполняется. В С++ можно использовать одно имя функции для множества различных действий. Это называется перегрузкой функций (function overloading). Здесь функция myFunction() перегружена тремя различными списками параметров. Версии отличаются типами и количество параметров В результате перегрузки функций происходит явление, называемое полиморфизмом функций. Полиморфная функция – это функция, отличающаяся многообразием форм. В более общем смысле, концепцией полиморфизма является идея "один интерфейс, множество методов". Это означает, что можно создать общий интерфейс для группы близких по смыслу действий. Преимуществом полиморфизма является то, что он помогает снижать сложность программ, разрешая использование того же интерфейса для задания единого класса действий. Выбор же конкретного действия, в зависимости от ситуации, возлагается на компилятор. • Полиморфизм может применяться также и к операторам. Фактически во всех языках программирования ограниченно применяется полиморфизм, например, в арифметических операторах. Так, например, в Си, символ + используется для складывания целых, длинных целых, символьных переменных и чисел с плавающей точкой. В этом случае компилятор автоматически определяет, какой тип арифметики требуется. В С++ вы можете применить эту концепцию и к другим, заданным вами, типам данных. Такой тип полиморфизма называется перегрузкой операторов (operator overloading). • Ключевым в понимании полиморфизма является то, что он позволяет вам манипулировать объектами различной степени сложности путём создания общего для них стандартного интерфейса для реализации похожих действий. Шаблоны Родовые(Шаблонные) Функции Родовые(Шаблонные) Классы Родовые функции • Родовая функция определяет базовый набор операций, которые будут применяться к разным типам данных. • Родовая функция оперирует с тем типом данных, который она получает в качестве параметра. • Создается с помощью ключевого слова template (предназначено для создания шаблона (или каркаса), который описывает то, что будет делать функция, при этом компилятору остается дополнить каркас необходимыми деталями). • Типовая форма определения функции-шаблона: Template <class фтип> возвр_значение имя_функции(список_параметров) { Тело функции } Пример: Создается родовая функция, которая меняет местами значения двух переменных, передаваемых ей в качестве параметров. Поскольку в своей основе процесс обмена двух значений не зависит от типа переменных, это процесс удачно реализуется с помощью родовой функции. • Ключевое слово template в определении родовой функции не обязательно должно быть в той же строке, что и имя функции •Вместо ключевого слова class можно указывать ключевое слово typename •Между инструкцией template и началом определения родовой функции не может быть других инструкций. •С помощью инструкции template можно определить более одного родового параметра, отделяя их друг от друга запятыми … в большинстве случаев, если нужны несколько разных версий функции для разных типов данных, вместо шаблонов лучше использовать перегруженные функции Родовые классы • Создается класс, в котором определены все необходимые алгоритмы, а фактические типы обрабатываемых данных задаются в качестве параметров позже, при создании объектов этого класса. Родовые классы полезны, когда класс содержит общую логику работы. Например, алгоритм, который реализует очередь целых, будет также работать и с очередью символов. С помощью родового класса можно создать класс, реализующий очередь, связанный список и т.д. для любых типов данных. Компилятор будет автоматически генерировать правильный тип объекта на основе типа, заданного при создании объекта. • Функции-члены родового класса сами автоматически становятся родовыми. Для них не обязательно явно задавать ключевое слово template. • В С++ имеется встроенная библиотека классовшаблонов, которая называется библиотекой стандартных шаблонов (Standard Template Library, STL). Библиотека предоставляет родовые версии классов для наиболее часто используемых алгоритмов и структур данных. В следующей программе создается очень простой родовой класс, реализующий односвязный список. Затем демонстрирую тся возможности такого класса путем создания связанного списка для хранения символов. Объявление родового класса похоже на объявление родовой функции. Тип данных, хранящихся в списке, становится родовым в объявлении класса. Но он не проявляется, пока не объявлен объект, который и задает реальный тип данных. В данном примере объекты и указатели создаются внутри функции Main(), где указывается, что типом хранящихся в списке данных является тип char.