Обьектно-ориентировое пронраммирование. Лекции по объектно-ориентированному программированию. Объектноориентированное программирование. Основные понятия
Скачать 185.04 Kb.
|
Объектно-ориентированное программирование. Основные понятия. Объектно-ориентированное программирование – это подход к построению программ, где главной отправной точкой служит объект с его свойствами и поведением. Основные принципы ООП были разработаны в языках Simula-67 (1967 – год создания) и Smalltalk, но в то время не получили широкого применения из-за трудностей освоения и низкой эффективности реализации. ООП оперирует с таким понятием как класс. Класс – это тип данных, определяемый пользователем. Класс представляет собой совокупность данных, характеризующих объект этого класса, и операций, которые могут быть с этими данными выполнены. Данные называют переменными-членами, полями или свойствами класса, а операции над данными – функциями- членами или методами класса. Существенным свойством класса является то, что детали его реализации скрыты от пользователей класса интерфейсом. Интерфейсом класса являются заголовки его методов. Объектом называется экземпляр класса, т. е. переменная, в качестве типа которой указано имя класса. Объекты взаимодействуют между собой, посылая и получая сообщения. Сообщение – это запрос на выполнение действия, содержащий набор необходимых параметров. Механизм сообщений реализуется с помощью вызова соответствующих функций. Таким образом, с помощью ООП можно легко реализовать событийно-управляемую модель, когда данные активны и управляют вызовом того или иного фрагмента программного кода. Примером событийно-управляемой модели может служить любая программа, управляемая с помощью меню. После запуска такая программа пассивно ожидает действия пользователя и должна уметь правильно отреагировать на любое из них. Следует заметить, что событийно-управляемая модель не является частью ООП и может быть реализована без использования объектов. Например, программирование на языке C под Windows с использованием функций API. Противоположностью событийной модели является директивная, когда код управляет данными: программа после старта предлагает пользователю выполнить некоторые действия в соответствии с жестко заданным алгоритмом. Объектно-ориентированное программирование обладает следующими свойствами: - инкапсуляция; - наследование; автор: Коломойцева Ирина Александровна, кафедра Прикладной математики и информатики, ДонНТУ 3 Класс данные функции - полиморфизм. Инкапсуляция (encapsulation) – это соединение в одной структуре данных (классе) данных и операций над данными в сочетании со скрытием ненужной для использования этих данных информации. Инкапсуляция повышает степень уровня абстракции программы, то есть данные класса и реализация его функций лежат ниже уровня абстракции и для написания программы информация о них не требуется. Инкапсуляция также позволяет изменить реализацию класса без модификации основной части программы, если интерфейс остался прежним. Инкапсуляция позволяет использовать класс в другом окружении и быть уверенным, что он не испортит не принадлежащие ему области памяти. А также создавать библиотеки классов для применения во многих программах. Наследование означает такое соотношение между классами, когда один класс использует структурную или функциональную часть (свойства) одного или нескольких других классов (соответственно, мы имеем простое или множественное наследование). Свойства повторно не описываются, что сокращает объем программы. Класс, использующий данные или методы другого класса, называется производным или подклассом, или субклассом. Класс, который предоставляет свои данные и методы другому классу, называется базовым или надклассом, или суперклассом. Иерархия классов представляется в виде древовидной структуры, в которой более общие классы располагаются ближе к корню, а более специализированные – на ветвях и листьях. В C++ каждый класс может иметь сколько угодно потомков и предков. Полиморфизм – это свойство ООП, при котором одно и тоже имя может вызывать различные действия на этапе выполнения. Самый простой пример полиморфизма – перегрузка функций, когда из нескольких вариантов выбирается наиболее подходящая функция по соответствию ее прототипа передаваемым параметрам. Второй пример – использование шаблонов функций, когда один и тот же код видоизменяется в соответствии с типом, переданным в качестве параметра. Но чаще всего понятие полиморфизма связывается с механизмом виртуальных методов. Описание класса Описание класса приблизительно выглядит так: class <имя> { [private:] <описание скрытых элементов> protected: <описание защищенных элементов> public: <описание доступных элементов> }; // описание заканчивается точкой с запятой обязательно!!! Управление доступом к элементам класса автор: Коломойцева Ирина Александровна, кафедра Прикладной математики и информатики, ДонНТУ 4 Главная задача класса – скрыть как можно больше информации. Существует три вида пользователей класса: – сам класс; – обычные пользователи; – производные классы. Каждый пользователь обладает разными уровнями доступа. Этих уровней три, и они описываются тремя словами: - private; - public; - protected. Любое объявление, появляющееся до ключевого слова управления доступом, считается приватным по умолчанию. Private – наиболее ограниченный доступ. Только сам класс (или классы, объявленные как дружественные (friend)) имеет доступ к приватным членам. Public – общедоступный уровень доступа. Свойства и методы с таким уровнем доступа могут использоваться любым пользователем. Protected – защищенный уровень доступа. Переменные и методы такого уровня доступа могут использоваться самим классом и классами, порожденными от него. Свойства полей класса Поля класса: – могут иметь любой тип, кроме типа этого же класса, но могут быть указателями или ссылками на этот класс; – могут быть описаны с модификатором const, при этом они инициализируются только один раз (с помощью конструктора) и не могут изменяться; – могут быть описаны с модификатором static, но не с auto, extern и register. Инициализация полей при описании не допускается, так как память под класс не выделяется, пока не будет создан экземпляр класса Виды классов Классы бывают: – глобальные (объявленные вне любого блока); – локальные объявленные внутри блока, например, функции или другого класса). Свойства локальных классов – внутри локального класса можно использовать типы, статические (static) и внешние (extern) переменные, внешние функции и элементы перечислений из области, в которой он описан; запрещается использовать автоматические переменные из этой области; – локальный класс не может иметь статических элементов; – методы этого класса могут быть описаны только внутри класса; автор: Коломойцева Ирина Александровна, кафедра Прикладной математики и информатики, ДонНТУ 5 – если один класс вложен в другой класс, они не имеют каких-либо особых прав доступа к элементам друг друга и могут обращаться к ним только по общим правилам. Пример определения класса class point { double x,y; public: point(double xVal=0.0, double yVal=0.0) {x=xVal, y=yVal;} void PutPoint (double xVal, double yVal); double GetX() {retun x;} double GetY(){retun y;} }; Приведен классический способ организации методов доступа к членам класса: все переменные являются закрытыми (private), а все методы - открытыми (public). Все методы имеют непосредственный доступ к скрытым полям класса, то есть тела функций класса входят в область видимости private элементов класса. В приведенном примере содержится три определения методов и одно объявление (PutPoint). Если тело метода определено внутри класса, он является встроенным (inline). Как правило, встроенными делают короткие методы. Если внутри класса записано только объявление (заголовок) метода, сам метод должен быть определен в другом месте программы. Выполняется это при помощи операции доступа к области видимости (::): void point::PutPoint (double xVal, double yVal) {x=xVal, y=yVal;} Такой код реализации называется внешним. Чтобы дать указание компилятору рассматривать функцию, реализованную вне класса, как встроенную, необходимо использовать ключевое слово inline. Например: inline void point::PutPoint (double xVal, double yVal) {x=xVal, y=yVal;} Описание объектов Создание объекта может происходить по одному из трех сценариев: 1) создание объектов с инициализацией по умолчанию; 2) создание объектов со специальной инициализацией; 3) создание объектов путем копирования других объектов. point p; //объект класса point с параметрами по умолчанию point p1(10,10); //объект с явной инициализацией point p2[200]; //массив объектов с параметрами по умолчанию point *p3 = new point(10); //динамический объект (второй параметр // задается по умолчанию) point &p4=p1; автор: Коломойцева Ирина Александровна, кафедра Прикладной математики и информатики, ДонНТУ 6 При создании каждого объекта выделяется память, достаточная для хранения всех его полей, и автоматически вызывается конструктор, выполняющий их инициализацию. При выходе объекта из области видимости он уничтожается, при этом автоматически вызывается деструктор. Доступ к элементам объекта аналогичен доступу к полям структуры. Для этого используется операция . (точка) при обращении к элементу через имя объекта и операция -> при обращении через указатель. Например: p.PutPoint(40,60); cout< cout< GetY()< Указатель this Каждый объект содержит свой экземпляр полей класса. Методы класса находятся в памяти в единственном экземпляре и используются всеми объектами совместно. Поэтому возникает необходимость обеспечить работу методов с полями именно того объекта, для которого они были вызваны. Это обеспечивается передачей в функцию скрытого параметра this, в котором хранится константный указатель на вызвавший функцию объект. Указатель this неявно используется внутри метода для ссылок на элементы объекта. В явном виде этот указатель применяется в основном для возвращения из метода указателя (return this;) или ссылки (return *this;) на вызвавший объект. Пример. Определим метод, который из двух точек возвращает ссылку на ту, у которой больше координата x. Первая точка вызывает метод, вторая передается в качестве параметра. point &the_greater(point &p) { if (x>p.GetX()) return *this; return p; } … point p(20,20); point p1(10,10); point &Greater=p.the_greater(p1); // новый объект инициализируется полями объекта p. Указатель this можно также применять для идентификации поля класса в том случае, когда его имя совпадает с именем формального параметра метода. Другой способ идентификации поля использует операции доступа к области видимости. автор: Коломойцева Ирина Александровна, кафедра Прикладной математики и информатики, ДонНТУ 7 void MovePoint(double x, double y) { this->x+=x; point::y+=y; } Перегрузка функций Перегрузка – это придание функции более чем одного значения, то есть имя у функции остается прежним, а параметры и действия могут быть разными. Конструкторы Конструктор – это метод, который вызывается при создании объекта и производит инициализацию переменных членов. Это метод имеет такое же имя, как и класс. Свойства конструкторов: – конструктор не возвращает значение, даже типа void; нельзя получить указатель на конструктор; – класс может иметь несколько конструкторов с разными параметрами для разных видов инициализации (при этом используется механизм перегрузки); – конструктор, вызываемый без параметров, называется конструктором по умолчанию; – параметры конструктора могут иметь любой тип, кроме этого же класса; можно задать параметры по умолчанию, но их может содержать только один из конструкторов; – если программист не указал ни одного конструктора, то компилятор создаст его автоматически; – конструкторы не наследуются; – конструкторы нельзя описывать с модификаторами const, virtual и static; – конструкторы глобальных объектов вызываются до вызова функции main; локальные объекты создаются, как только становится активной область их действия; конструктор запускается и при создании временного объекта (например, при передаче объекта из функции); – конструктор вызывается, если в программе встретилась какая-либо из синтаксических конструкций: имя_класса имя_объекта [(список параметров)]; //список параметров не должен быть пустым имя_класса (список параметров); //создается объект без имени (список параметров может быть пустым) имя_класса имя_объекта = выражение; //создается объект без имени и копируется Например, автор: Коломойцева Ирина Александровна, кафедра Прикладной математики и информатики, ДонНТУ 8 point p1(10,10), p2(20), p3; point p4 = point(100); point p5 = 200; В первом операторе создаются три объекта. Значения не указанных параметров устанавливаются по умолчанию. Во втором операторе создается безымянный объект со значением параметра x=100 (значение второго параметра устанавливается по умолчанию). Выделяется память под объект p4, в которую копируется безымянный объект. Во третьем операторе создается безымянный объект со значением параметра x=200 (значение второго параметра устанавливается по умолчанию). Выделяется память под объект p5, в которую копируется безымянный объект. Такая форма создания объекта возможна в том случае, если для инициализации объекта допускается задать один параметр. Пример. Использование перегруженных конструкторов. enum color {red, green, blue}; class point { double x,y; color cp; char *name; public: point(double xVal=0.0, double yVal=0.0); point(color cl); point(char *np); … }; point::point(double xVal, double yVal) {x=xVal; y=yVal;} point::point(color cl) { switch (cl) { case red: x=100;y=100;cp=red;name=0;break; case green: x=200;y=200;cp=green;name=0;break; case blue: x=300;y=300;cp=blue;name=0;break; } } point::point(char *np) { name=new char[strlen(np)+1]; strcpy(name,np); x=100; y=100; cp=red; } автор: Коломойцева Ирина Александровна, кафедра Прикладной математики и информатики, ДонНТУ 9 … point p1(10,10),p2(10),p3; point p4(green); point p5("X1"); Есть еще один способ инициализации полей в конструкторе – с помощью списка инициализаторов, расположенных после двоеточия между заголовком и телом конструктора. Деструкторы Деструкторы - это функции, которые используются для выполнения определенных операций при удалении объекта. Обычно деструкторы выполняют операции, обратные тем, которые выполняли конструкторы. Например, если конструктор выделяет динамическую память для членов класса, то деструктор ее освобождает. Деструктор вызывается автоматически, 4 – для локальных объектов – при выходе из блока, в котором они объявлены; – для глобальных – как часть процедуры выхода из main; – для объектов, заданных через указатели, деструктор вызывается неявно при использовании операции delete (автоматический вызов деструктора объекта при выходе из области действия указателя на него не производится). Между конструктором и деструктором существует ряд различий. 1. Деструкторы могут быть виртуальными, а конструкторы – нет. 2. Деструкторам нельзя передавать аргументы. 3. В каждом классе может быть объявлен только один деструктор. Имя деструктора состоит из имени класса, перед которым стоит (тильда). class point {… public: point () {x=0; y=0;} point() {}; … }; Статические элементы класса Статические поля и методы объявляются с помощью модификатора static. Их можно рассматривать как глобальные переменные или функции, доступные только в пределах области класса. Статические поля Статические поля применяются для хранения данных, общих для всех объектов класса, например, количества объектов или ссылки на разделяемый всеми объектами ресурс. Эти поля существуют для всех объектов класса в единственном экземпляре, то есть не дублируются. автор: Коломойцева Ирина Александровна, кафедра Прикладной математики и информатики, ДонНТУ 10 |