Тема 7. Введение в объектно-ориентированное программирование.



Принципы объектно-ориентированного программирования.

Ранее мы использовали методы процедурно ориентированного программирования, в которых программа структурируется так, что имеется главная функция и, возможно, несколько других функций, вызывающихся из главной. Это – подход «сверху - вниз». программа начинается с первого оператора главной функции и заканчивается последней командой этой же функции. При таком подходе код и данные разделены. Процедуры определяют, что происходит с данными, но никогда не бывает наоборот.

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

Преимущества ООП:

§ Программы легче читать и понимать, т.к. программист видит только необходимые детали.

§ Программы легко модифицируются. Для изменения программы достаточно убрать или добавить объекты.

§ Объекты можно использовать многократно.

Недостатком ООП можно считать то, что практически невозможно процедурно ориентированную программу превратить в объектно ориентированную.

Терминология объектно-ориентированного программирования.

ООП – это метод программирования, позволяющий рассматривать модель решаемой задачи как набор объектов. манипулировать с объектами можно при помощи сообщений, которые напоминают вызовы функций в процедурно ориентированной программе. Когда объект получает сообщение, на него реагируют методы, содержащиеся в этом объекте. Методы аналогичны функциям, однако они являются частью объекта.

Классы С++ являются расширением типа С и С++ struct и образуют необходимый абстрактный тип данных для ООП. Объект представляет собой экземпляр класса.

Основными понятиями, на которых основано ООП являются инкапсуляция, наследование и полиморфизм.

Инкапсуляция – это способ объединения данных объекта и функций-членов в единую структуру.

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

Полиморфизм – это концепция, смысл которой в следующем: одни и те же сообщения можно посылать объектам родительского класса и объектам всех производных классов. Полиморфизм позволяет каждому объекту подкласса реагировать по-своему на одинаковые сообщения.

Благодаря полиморфизму объекты могут реагировать на сообщения из программ, даже если точный тип объекта неизвестен. В С++ эта возможность реализуется с помощью механизма виртуальных функций. При использовании виртуальных функций сообщения передаются не непосредственно объекту, а в виде указателя, ссылающегося на объект. Для адресации виртуальные функции используют таблицу, которая инициализируется на этапе выполнения.

Структура как простейший класс.

Структура в С++ напоминает простейший класс. Рассмотрим пример:

#include <iostream.h>

#include <math.h>

struct math_operation

{

double data;

void setValue(double ang){data=ang;}

double getSquare(){return data*data;}

double getSquareRoot{return sqrt(data);}

}

math_operation math;

int main()

{

math.setValue(35.63);

cout<<”x^2=”<<math.getSquare();

cout<<”square root=”<<math.getSquareRoot();

return 0;

}

Внутри структуры содержатся описания данных и функций-членов.

В данном примере имеется единственный элемент данных “double data” и три функции-члена.

Синтаксис и правила для классов С++.

Описание класса С++ начинается с ключевого слова class. Оформление определения класса очень похоже на описание struct.

class имя_класса

{

       тип переменная1;

       тип переменная2;

             …

       функция-член1

       функция-член2

             …

public:

       тип переменная3;

       тип переменная4;

             …

       функция-член3

       функция-член4

             …

};

По умолчанию члены класса являются частными (private). Они доступны только функциям-членам. После объявления public следуют данные и функции, доступные внешним для класса функциям. Предыдущий пример должен быть записан следующим образом:

#include <iostream.h>

#include <math.h>

class math_operation

{

       double data;

public:

       void setValue(double ang){data=ang;}

       double getSquare(){return data*data;}

       double getSquareRoot(){return sqrt(data);}

}

math_operation math;

int main()

{

       math.setValue(35.63);

       cout<<”x^2=”<<math.getSquare();

       cout<<”square root=”<<math.getSquareRoot();

       return 0;

}

Теперь к переменной data доступ возможен только через функции-члены класса.

Внутри описания класса может быть указан только прототип метода. Сам метод может быть написан вне описания и даже в другом файле. В этом случае заголовок метода выглядит следующим образом:

возвращаемыйТип имяКласса::имяМетода(список аргументов){код метода}

 

Inline методы.

В ООП программах встречается множество коротких методов. Код вызова таких методов может оказаться более длинным, чем сам метод. В этом случае метод может быть объявлен с описателем inline.Для них компилятор не создает отдельную функцию, а вставляет код метода непосредственно в каждое место вызова.

Пример:

inline double math_operation::getSquareRoot()

{

return sqrt(data);

}

Действует следующее соглашение, если код метода написан непосредственно внутри описания класса, то он автоматически считается inline.

Указатель this.

При описании класса автоматически объявляется переменная с именем this. Она указывает на текущий экземпляр класса:

ИмяКласса *this;

Его можно использовать в случаях, когда возникает неоднозначность в именах, для явного вызова конструкторов класса, для возврата указателя на текущий объект в методах класса.

Конструкторы и деструкторы.

Особенность ООП в том, что некоторые методы выполняются неявно. К ним относятся конструктор и деструктор.

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

1. конструктор без параметров (используемый по умолчанию) и

2. конструктор, создающий копию объекта (копиконструктор).

Если они не включены в описание класса, то компилятор создает их самостоятельно.

Деструктор вызывается при уничтожении объекта. Он обычно используется для освобождения памяти. Деструктор имеет имя, совпадающее с именем класса, но впереди имени ставится знак ‘~’ (тильда), параметров не имеет.

Примеры:

class coins

{

       int number;

public:

       coins(){number=0;}

       coins(int n){number=n;}

       coins(coins &c){number=c.number;}

       ~coins(){cout<<”Finish\n”;}

       int convertToRoubles(){return number*0.01;}

};

 

class stringOperation

{

       char *str;

       int lenght;

public:

       stringOperation(){str=NULL;n=0;}

       stringOperation(int n){str=new char[n];lenght=n;}

       stringOperation(stringOperation &a)

       {

             this(a.n);

             memcpy(str,a.str,n);

       }

       ~stringOperation(){delete str;}

       void indata()

{

cin>>lenght;

for(int i=0;i<lenght;i++)cin>>str[i];

       }

       void outdata()

{

cout<<lenght<<newline;

for(int i=0;i<lenght;i++)cout<<str[i];

cout<<newline;

       };

 

Перегрузка методов класса.

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

Пример:

class module

{

public:

       int mod(int n){return abs(n);}

       double mod(double n){return fabs(n);}

};

void main()

{

       module m;

       int a=-10;

       cout<<m.mod(a);

       double b=-1.5;

       cout<<m.mod(b);

}

Перегрузка операций.

Для класса можно определить свои собственные операции. Такая возможность называется перегрузкой операций. Можно перегружать все арифметические и логические операции, операции присваивания, квадратные и круглые скобки, операции new и delete.

Синтаксис метода, перегружающего операцию:

ВозвращаемыйТип operator перегружаемаяОперация(параметры){код}

Пример:

coins coins::operator+(coins a)

{

       coins res;

       res.number=this->number+a.number;

       return res;

}

Практическое задание.

Вариант A.

Разработайте класс "Вектор", определите набор основных операций между ними. Умножение векторов определите как скалярное произведение векторов  и  в эвклидовой метрике в :

Предусмотрите возможности сохранения векторов на диске и восстановления их из файла.

Вариант В.

Разработайте класс "Комплексное число", определите набор основных операций между ними и исследуйте в какие точки переводятся точки фигуры

преобразованиями

Вариант C.

См. вариант B. Для преобразований:


Дата добавления: 2018-02-15; просмотров: 821; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!