Программирование

134
Программирование Часть 6. Основы ООП Динамические структуры данных

Upload: quinta

Post on 07-Jan-2016

39 views

Category:

Documents


0 download

DESCRIPTION

Программирование. Часть 6 . Основы ООП Динамические структуры данных. 5. Объектно-ориентированное программирование 5. 1 . Декомпозиция: divide et impera. Современные программные системы – сложные системы: они отражают сложность реального мира; - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Программирование

Программирование

Часть 6. Основы ООПДинамические структуры данных

Page 2: Программирование

Современные программные системы – сложные системы: они отражают сложность реального мира; процесс их разработки сложен (и слабо стандартизирован); программа - дискретная система, а дискретные системы неустойчивы:

маленькая ошибка приводит к значительным последствиям. Общие свойства сложных систем:

Имеют внутреннюю структуру, то есть состоят из компонент - подсистем, которые, в свою очередь, тоже могут быть разбиты на подсистемы.

Внутренние связи подсистем сильнее связей между этими подсистемами. Это дает возможность по отдельности изучать каждую часть.

Состоят из ограниченного числа типов подсистем, скомбинированных и организованных различным образом.

Являются результатом эволюции более простых систем.

5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera

2

Page 3: Программирование

Рост сложности и объема ПО на примере ОС Windows (неофициальные данные):

Последствия ошибок: Состоят из ограниченного числа типов подсистем, скомбинированных и

организованных различным образом. Являются результатом эволюции более простых систем.

5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera

3

Операционная система

Год выпуска

Кол-во строк исходного кода

Windows NT 3.5 1994 4 миллиона

Windows NT 4.0 1996 16,5 миллионов

Windows 2000 2000 20 миллионов

Windows XP 2002 40 миллионов

Page 4: Программирование

Сложности разработки: Служба Microsoft Consulting Services провела анализ результатов

выполнения большого количества своих программных проектов. Оказалось, что вероятность провала программных проектов довольно

велика. Только 24% проектов можно признать в той или иной степени

успешными, 26% не были завершены, 50% столкнулись с большими проблемами, например, бюджет был

превышен вдвое или затрачено в 1,5 раза больше времени.

5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera

4

Page 5: Программирование

Последствия маленьких ошибок – крах программной системы: 1996 год. Ошибка взятия целой части дробного числа при выходе числа

с плавающей точкой за диапазон допустимых 16-битовых целых:

double x;…short i = x;…

Вместо:double x;…

if (abs (x) < 32 767) short i = x;else …;

Результат:

5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera

5

Page 6: Программирование

5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera

6

4 июня 1996 года

Взрыв ракеты-носителя Ariane 5спустя 30 секунд после запуска.

Page 7: Программирование

Способ преодоления сложности – декомпозиция При проектировании сложной программной системы необходимо

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

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

Построив более простую модель, ее можно далее развивать, следуя за развитием системы.

В этом случае мы не превысим пропускную способность

человеческого мозга: для понимания любого уровня системы необходимо держать в памяти информацию лишь о немногих частях системы.

5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera

7

Page 8: Программирование

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

Объектно-ориентированная декомпозиция Мир представляется совокупностью автономно действующих

объектов, моделирующих объекты реального мира. Каждый объект обладает своим собственным поведением. Послав объекту сообщение, можно попросить его выполнить

присущее ему действие. Объекты взаимодействуют друг с другом, моделируя поведение

системы, соответствующее более высокому уровню. Реализуется средствами объектно-ориентированного

программирования.

5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera

8

Page 9: Программирование

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

5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera

9

Page 10: Программирование

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

 Структурная иерархия строится по простому принципу разделения целого на составные части:

5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera

10

Животное

ТуловищеГолова

Глаза РотУши Лапы Хвост……

Page 11: Программирование

Объектная иерархия строится по принципу наследования свойств родительских (вышележащих) классов объектов дочерними (нижележащими) классами.

Родительские классы называют просто родителями (предками), дочерние – потомками

Птица, собака, волк – это типы животных, называемые классами. Конкретная реализация того или иного класса, например, кот

Матроскин, является объектом данного класса.

5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera

11

Животное

ПтицаМлекопитающее

Кошка ВолкСобака Орел Воробей……

Page 12: Программирование

Объект характеризуется: совокупностью своих элементов (и их текущих значений совокупностью допустимых для объекта действий

Объединение в едином объекте «материальных» составных частей (обрабатываемых данных), защищенных от внешних воздействий, и действий, манипулирующих этими частями (данными) называют инкапсуляцией.

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

объектов. (Не существует конкретного живого организма, который назывался бы млекопитающее Бобик). Такие классы называют абстрактными.

Конкретные экземпляры объектов относятся, как правило, к классам самых нижних уровней объектной иерархии (собака Бобик, кот Матроскин).

Полиморфизм – это свойство различных объектов выполнять одно и то же действие (с одним и тем же названием) по-своему.

Родительские типы называют просто родителями (предками), дочерние – потомками

5. Объектно-ориентированное программирование 5.2. Три принципа ООП

12

Page 13: Программирование

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

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

Объект (экземпляр класса) находится в таком же отношении к своему классу, в каком переменная находится по отношению к своему типу.

Данные и функции внутри класса называются членами класса. Данные, входящие в класс, называются данными-членами или

полями. Функции, принадлежащие классу, называют функциями-членами

или методами.

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

13

Page 14: Программирование

Синтаксис объявления класса, который не является наследником никакого другого класса:

class Имя_Класса {

закрытые данные и функции спецификатор доступа: данные и функции спецификатор доступа: данные и функции… спецификатор доступа: данные и функции};

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

14

Данные

Имя_Класса

Функции

Page 15: Программирование

Пример описания простейшего класса, включающего только данные:

class СBox { public: double m_length; double m_width; double m_height;};

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

15

m_length m_width

m_height

Page 16: Программирование

Пример описания простейшего класса, включающего только данные:

class СBox { public: double m_length; double m_width; double m_height;};

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

16

Спецификатор доступа

Спецификатор доступа

Page 17: Программирование

Спецификатор доступа определяет, где в программе будут доступны описанные за ним члены класса.

Имеются 3 спецификатора доступа: Public – члены класса будут доступны как в классе, так и в

любой точке программы внутри области видимости класса, к которому они относятся.

Private (спецификатор по умолчанию) – члены класса будут доступны только внутри класса (членам класса)

Protected – члены класса будут доступны только внутри класса и внутри потомков класса

Действие спецификатора доступа распространяется до следующего спецификатора или до конца описания класса

По умолчанию, все члены класса, объявленные после ключевого слова class до первого спецификатора доступа имеют спецификацию доступа private

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

17

Page 18: Программирование

Объявление экземпляров классаCBox mybox1, mybox2;

Объявление указателей на классCBox *pbox;pbox=&mybox1;

Динамическое выделение памяти для экземпляра классаCBox *pmybox = new CBox;

Доступ к членам – аналогично структурамmybox1.m_length = 2.5;mybox2.m_width = mybox1.m_length;pmybox->m_height = mybox1.m_length;pmybox->m_length = pmybox->m_height ;

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

18

Page 19: Программирование

Первый принцип инкапсуляции: объединение данных и методов. Добавим функцию вычисления объема

class СBox { public: double m_length; double m_width; double m_height;

double Volume( );};

double CBox::Volume(){ return m_length*m_width*m_height;}

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

19

Page 20: Программирование

Поработаем с классом CBox

int main() // Working with class CBox{ CBox mybox1; // Static allocation mybox1.m_length=2; mybox1.m_width=3; mybox1.m_height=4; cout << mybox1.Volume() << endl; // 24

CBox *pmybox2 = new CBox; // Dynamic allocation pmybox2->m_length=5; pmybox2->m_width=6; pmybox2->m_height=7; cout << pmybox2->Volume() << endl; // 210 delete pmybox2; return 0;}

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

20

Page 21: Программирование

Второй принцип инкапсуляции: защита от внешнего вмешательства. Доступ к данным через явный интерфейс

class CBox{ double m_length; double m_width; double m_height; public:

void Setlength(double sl) {m_length = sl; } void Setwidth(double sw) {m_width=sw; }

void Setheight(double sh) {m_height =sh; } double Getlength() {return m_length;} double Getwidth() {return m_width;}

double Getheight() {return m_height;} double Volume( );

};

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

21

Page 22: Программирование

Работаем с измененным классом CBox:

int main() // Working with modified class CBox{ CBox mybox1; mybox1.Setlength(2); mybox1.Setwidth(3); mybox1.Setheight(4); cout << mybox1.Getheight() << " " << mybox1.Volume() << endl; // 4 24

CBox *pmybox2 = new CBox; pmybox2->Setlength(5); pmybox2->Setwidth(6); pmybox2->Setheight(7); cout << pmybox2->Getlength() << " " << pmybox2->Volume() << endl; delete pmybox2; return 0;}

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

22

Page 23: Программирование

Для чего это нужно: независимость интерфейса от реализации, разрешаются только операции, определенные через интерфейсclass CBox{ double m_Size[3]; //now with array !!!public:

void Setlength(double sl) {m_Size[0] = sl; } void Setwidth(double sw) {m_Size[1]=sw; }

void Setheight(double sh) {m_Size[2] =sh; } double Getlength() {return m_Size[0];} double Getwidth() {return m_Size[1];}

double Getheight() {return m_Size[2];} double Volume( );

};double CBox::Volume(){ return Getlength()*Getwidth()*Getheight();}

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

23

Page 24: Программирование

В использующей класс программе ничего менять не надо:

int main() // Working with modified class CBox{ CBox mybox1; mybox1.Setlength(2); mybox1.Setwidth(3); mybox1.Setheight(4); cout << mybox1.Getheight() << " " << mybox1.Volume() << endl;

CBox *pmybox2 = new CBox; pmybox2->Setlength(5); pmybox2->Setwidth(6); pmybox2->Setheight(7); cout << pmybox2->Getlength() << " " << pmybox2->Volume() << endl; delete pmybox2; return 0;}

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

24

Page 25: Программирование

Конструкторы Конструктор класса – специальная функция класса, которая

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

Конструкторы всегда называются по имени класса и не имеют типа возврата.

Компилятор предоставляет два типа конструкторов: конструктор по умолчанию и конструктор копирования:

CBox mybox1; // Вызов конструктора по умолчанию… CBox mybox2 = mybox1 // Вызов конструктора копирования

Класс может иметь несколько конструкторов, которые можно перегружать Если Вы определили какой-либо свой конструктор копирования, Вы обязаны

явно определить конструктор по умолчанию. Стандартный конструктор копирования нельзя использовать при работе с

указателями

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

25

Page 26: Программирование

Класс Cbox с перегруженным конструктором и тестовым деструктором

class CBox { double m_length; double m_width; double m_height;public: CBox() {m_length=0; m_width=0; m_height=0;} CBox(double l,double w) {m_length=l; m_width=w; m_height=0;} CBox(double l, double w, double h){m_length=l; m_width=w; m_height=h;} ~CBox () {std::cout << "destructor CBox done";} void Setlength(double sl) {m_length = sl;} void Setwidth(double sw) {m_width=sw;} void Setheight(double sh) {m_height =sh;} double Getlength() {return m_length;} double Getwidth() {return m_width;} double Getheight() {return m_height;}

void Print (){std::cout <<"\nL="<<m_length<<" W="<<m_width<<" H="<<m_height;} double Volume( ){return m_length*m_width*m_height;}};

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

26

Page 27: Программирование

В конструкторе инициализацию переменных-членов класса можно делать в теле конструктора:

CBox() {m_length=0; m_width=0; m_height=0;}

CBox(double l,double w) {m_length=l; m_width=w; m_height=0;}

CBox(double l, double w, double h){m_length=l; m_width=w; m_height=h;}

Или вне тела:

CBox() : m_length(0), m_width(0), m_height(0) { }

CBox(double l,double w): m_length(l), m_width(w), m_height(0) { }

CBox(double l, double w, double h): m_length(l), m_width(w), m_height(h) { }

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

27

Page 28: Программирование

Поработаем с этим классом

int main() // Working with class CBox{

CBox mybox1; mybox1.Print(); // L=0 W=0 H=0CBox mybox2(1,2,3); mybox2.Print(); // L=1 W=2 H=3CBox mybox3(1,2); mybox3.Print(); // L=1 W=2 H=0 CBox mybox4=mybox2; mybox4.Print(); // L=1 W=2 H=3

mybox1=mybox2; mybox1.Print(); // L=1 W=2 H=3 _getch();return 0; // Destructor done}

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

28

Page 29: Программирование

Стандартный конструктор копирования нельзя использовать, если Вы работаете с членами - указателями

class CPoint{

short m_a;short *m_k;

public:CPoint() {m_a=4; m_k=new short (1);} // Consructor

~CPoint() {delete m_k; m_k=NULL;} // Destructor

void Setk(short k) {*m_k=k;}void Seta(short a) {m_a=a;}void Print ()

{std::cout << "\n a="<<m_a<<" k=" << m_k<< " *k="<<*m_k;}};

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

29

Page 30: Программирование

Стандартный конструктор копирования нельзя использовать, если Вы работаете с членами - указателями

int main() // Working with class CPoint{ CPoint x; x.Print(); // a= 4 k=003B6188 *k=1 CPoint y=x; y.Print(); // a= 4 k=003B6188 *k=1

x.Setk(5); x.Seta(8);

x.Print(); // a= 8 k=003B6188 *k=5 y.Print(); // a= 4 k=003B6188 *k=5

return 0; // program crash while try to free the same} // memory second time!

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

30

Page 31: Программирование

Надо определить свой конструктор копирования

class CPoint{ short m_a; short *m_k;public: CPoint() {m_a=4; m_k=new short (1);} CPoint (const CPoint &p) {m_a=p.m_a; m_k=new short(*p.m_k);} ~CPoint() {delete m_k; m_k=NULL;}

void SetK(short k) {*m_k=k;} void SetA(short a) {m_a=a;} void Print () {std::cout << "\n a="<<m_a<<" k=" << m_k<< " *k="<<*m_k;}};

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

const, чтобы Вы по глупости не изменили значения полей

источника в функции при их копировании

Если передавать p не по ссылке, а по значению, произойдет зацикливание

функции, так как передача по значению предполагает создание

нового объекта и копирование значения, которое тоже выполняется с

помощью этой функции

31

Page 32: Программирование

Та же программа, теперь дает ожидаемый результат

int main() // Working with class CPoint{ CPoint x; x.Print(); // a= 4 k=003B6188 *k=1 CPoint y=x; y.Print(); // a= 4 k=003B6260 *k=1

x.SetK(5); x.SetA(8);

x.Print(); // a= 8 k=003B6188 *k=5 y.Print(); // a= 4 k=003B6260 *k=1

return 0;}

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

32

Page 33: Программирование

Деструкторы Деструктор класса – специальная функция класса, которая

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

Имя деструктора совпадает с именем класса, которому предшествует знак ~(тильда).

Деструктор не принимает параметров и не возвращает значения. Таким образом, деструктор в классе всегда один.

Компилятор предоставляет деструктор по умолчанию. Однако, если Вы захватывали какие-либо ресурсы при создании

объекта (например, динамически выделяли память), Вы обязаны переопределить деструктор для корректного освобождения ресурсов

Это было сделано в предыдущем примере:~CPoint() {delete m_k; m_k=NULL;}

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

33

Page 34: Программирование

Объекты в памяти

CBox box1, box2, box3

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

box1 box2 box3

m_length

m_width

m_height

Setheight()

Setwidth()

Setlength()

Getheight()

Getwidth()

Getlength()

Volume()

m_length

m_width

m_height

m_length

m_width

m_height

34

Page 35: Программирование

Указатель this

double CBox::Volume(){ return m_length * m_width * m_height;}box1.Volume(); box2.Volume(); box3.volume()

double CBox::Volume(const CBox* this){ return this->m_length * this->m_width * this->m_height;} CBox::Volume(&box1);

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

35

Page 36: Программирование

Статические переменные или константы - члены классаclass CBox{ double m_length; double m_width; double m_height;

static int m_noboxes;

public: CBox() {m_length=0; m_width=0; m_height=0; m_noboxes++}

void Setlength(double sl) {m_length = sl; } void Setwidth(double sw) {m_width=sw; }

void Setheight(double sh) {m_height =sh; } double Getlength() {return m_length;} double Getwidth() {return m_width;}

double Getheight() {return m_height;} double Volume( );

};

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

Статические данные-члены класса только объявляются внутри класса. Они должны быть определены вне класса следующим образом:int CBox::m_noboxes; // или int CBox::m_noboxes=0;

36

Page 37: Программирование

Объекты в памяти

CBox box1, box2, box3;

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

box1 box2 box3

m_length

m_width

m_height

Setheight()

Setwidth()

Setlength()

Getheight()

Getwidth()

Getlength()

Volume()

m_length

m_width

m_height

m_length

m_width

m_height

m_noboxes

37

Page 38: Программирование

Статические функции - члены классаclass CBox{ double m_length; double m_width; double m_height;

static int m_noboxes; public:

CBox() {m_length=0; m_width=0; m_height=0; m_noboxes++} void Setlength(double sl) {m_length = sl; } void Setwidth(double sw) {m_width=sw; }

void Setheight(double sh) {m_height =sh; } double Getlength() {return m_length;} double Getwidth() {return m_width;}

double Getheight() {return m_height;} double Volume( ); static Getnoboxes() {return m_noboxes;}

};

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

Статические функции-члены класса имеют доступ только к статическим членам класса. Для доступа к нестатическим членам они должны получить адрес объекта как параметр

38

Page 39: Программирование

Константные объектыconst CBox bx1(10, 15, 6);

Константные функции-члены класса class CBox{ double m_length; double m_width; double m_height;

static int m_noboxes; public:

const double Getlength() {return m_length;} const double Getwidth() {return m_width;}

const double Getheight() {return m_height;} const double Volume( );

};

5. Объектно-ориентированное программирование 5.3. Инкапсуляция

Значения полей константного объекта после инициализации не могут изменяться

Константная функция не может изменять значения переменных-членов класса

39

Page 40: Программирование

Организация связанных структур данных.

struct Node{

Node *link;// Информационная часть inf// …

};

Inf link

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

Inf link Inf link Inf link

40

Page 41: Программирование

Основные виды связанных динамических структур данных:

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

Inf link Inf link Inf link Inf link

inf link1 link2 inf link1 link2 inf link1 link2

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

41

Page 42: Программирование

Основные виды связанных динамических структур данных:

Кольцевые списки – имеют дополнительную связь между первым и последним элементами.

inf link inf link inf link inf link

inf link inf link inf link inf link

Очередь – частный случай линейного списка – разрешено только 2 действия – добавление элементов в конец (хвост) и удаление из начала (головы) списка.Стек – частный случай линейного списка – разрешено только 2 действия – добавление и удаление элементов с одного конца (головы) стека.

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

42

Page 43: Программирование

Основные виды связанных динамических структур данных:

Деревья – иерархические динамические структуры произвольной конфигурации.

inf link1 link2

inf link1 link2

inf link1 link2

inf link1 link2

inf link1 link2 inf link1 link2

inf link1 link2 inf link1 link2

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

43

Page 44: Программирование

Стек как объект-контейнер

class CStack{

struct m_Node{

m_Node *m_next;int m_item;

};m_Node *m_head;int m_size;

public:CStack() {m_head=NULL; m_size=0;} //Constructor~CStack(); // Destructorvoid Push(int item);int Pull();void Print();

};

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

44

Page 45: Программирование

Работа со стеком1. Исходное состояние CStack() {m_head=NULL; m_size=0;}

2. Добавление элемента void CStack::Push(int item){ m_Node *cur=new m_Node; cur->m_item = item; cur->m_next = m_head; m_head = cur; m_size++; return;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_head

m_head cur

m_size=0

m_item m_next

45

Page 46: Программирование

Работа со стеком1. Исходное состояние CStack() {m_head=NULL; m_size=0;}

2. Добавление элемента void CStack::Push(int item){ m_Node *cur=new m_Node; cur->m_item = item; cur->m_next = m_head; m_head = cur; m_size++; return;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

m_head cur

m_size=0

46

Page 47: Программирование

Работа со стеком1. Исходное состояние CStack() {m_head=NULL; m_size=0;}

2. Добавление элемента void CStack::Push(int item){ m_Node *cur=new m_Node; cur->m_item = item; cur->m_next = m_head; m_head = cur; m_size++; return;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

m_head cur

m_size=0

47

Page 48: Программирование

Работа со стеком1. Исходное состояние CStack() {m_head=NULL; m_size=0;}

2. Добавление элемента void CStack::Push(int item){ m_Node *cur=new m_Node; cur->m_item = item; cur->m_next = m_head; m_head = cur; m_size++; return;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

m_head cur

m_size=0

48

Page 49: Программирование

Работа со стеком1. Исходное состояние CStack() {m_head=NULL; m_size=0;}

2. Добавление элемента void CStack::Push(int item){ m_Node *cur=new m_Node; cur->m_item = item; cur->m_next = m_head; m_head = cur; m_size++; return;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

m_head cur

m_size=1

49

Page 50: Программирование

Работа со стеком1. Исходное состояние CStack() {m_head=NULL; m_size=0;}

2. Добавление элемента void CStack::Push(int item){ m_Node *cur=new m_Node; cur->m_item = item; cur->m_next = m_head; m_head = cur; m_size++; return;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

m_head

m_size=1

50

Page 51: Программирование

Работа со стеком1. Исходное состояние CStack() {m_head=NULL; m_size=0;}

2. Добавление элемента void CStack::Push(int item){ m_Node *cur=new m_Node; cur->m_item = item; cur->m_next = m_head; m_head = cur; m_size++; return;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

m_head

m_size=1

51

Page 52: Программирование

Работа со стеком

2. Добавление еще одного элемента void CStack::Push(int item){ m_Node *cur=new m_Node; cur->m_item = item; cur->m_next = m_head; m_head = cur; m_size++; return;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

m_size=1

52

Page 53: Программирование

Работа со стеком

2. Добавление еще одного элемента void CStack::Push(int item){ m_Node *cur=new m_Node; cur->m_item = item; cur->m_next = m_head; m_head = cur; m_size++; return;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

m_size=1

cur

m_item m_next

53

Page 54: Программирование

Работа со стеком

2. Добавление еще одного элемента void CStack::Push(int item){ m_Node *cur=new m_Node; cur->m_item = item; cur->m_next = m_head; m_head = cur; m_size++; return;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

m_size=1

cur

m_item m_next

54

Page 55: Программирование

Работа со стеком

2. Добавление еще одного элемента void CStack::Push(int item){ m_Node *cur=new m_Node; cur->m_item = item; cur->m_next = m_head; m_head = cur; m_size++; return;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

m_size=1

cur

m_item m_next

55

Page 56: Программирование

Работа со стеком

2. Добавление еще одного элемента void CStack::Push(int item){ m_Node *cur=new m_Node; cur->m_item = item; cur->m_next = m_head; m_head = cur; m_size++; return;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

m_size=1

cur

m_item m_next

56

Page 57: Программирование

Работа со стеком

2. Добавление еще одного элемента void CStack::Push(int item){ m_Node *cur=new m_Node; cur->m_item = item; cur->m_next = m_head; m_head = cur; m_size++; return;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

m_size=2

cur

m_item m_next

57

Page 58: Программирование

Работа со стеком

3. Добавление еще одного элемента void CStack::Push(int item){ m_Node *cur=new m_Node; cur->m_item = item; cur->m_next = m_head; m_head = cur; m_size++; return;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

m_size=2

m_item m_next

58

Page 59: Программирование

Работа со стеком

4. Удаление элементаint CStack::Pull(){ int item=m_head->m_item; m_Node* tmp=m_head; m_head=m_head->m_next; delete tmp; m_size--; return item;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

m_size=2

m_item m_next

59

Page 60: Программирование

Работа со стеком

4. Удаление элементаint CStack::Pull(){ int item=m_head->m_item; m_Node* tmp=m_head; m_head=m_head->m_next; delete tmp; m_size--; return item;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

m_size=2

m_item m_next

item

60

Page 61: Программирование

Работа со стеком

4. Удаление элементаint CStack::Pull(){ int item=m_head->m_item; m_Node* tmp=m_head; m_head=m_head->m_next; delete tmp; m_size--; return item;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

m_size=2

m_item m_next

item

tmp

61

Page 62: Программирование

Работа со стеком

4. Удаление элементаint CStack::Pull(){ int item=m_head->m_item; m_Node* tmp=m_head; m_head=m_head->m_next; delete tmp; m_size--; return item;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

m_size=2

m_item m_next

item

tmp

62

Page 63: Программирование

Работа со стеком

4. Удаление элементаint CStack::Pull(){ int item=m_head->m_item; m_Node* tmp=m_head; m_head=m_head->m_next; delete tmp; m_size--; return item;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

m_size=2

m_item m_next

item

tmp

63

Page 64: Программирование

Работа со стеком

4. Удаление элементаint CStack::Pull(){ int item=m_head->m_item; m_Node* tmp=m_head; m_head=m_head->m_next; delete tmp; m_size--; return item;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

m_size=1

item

tmp

64

Page 65: Программирование

Работа со стеком

4. Удаление элементаint CStack::Pull(){ int item=m_head->m_item; m_Node* tmp=m_head; m_head=m_head->m_next; delete tmp; m_size--; return item;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

m_size=1

item

65

Page 66: Программирование

Работа со стеком

5. Печать элементовvoid CStack::Print(){ std::cout << "\nPrinting stack, size = " << m_size <<"\n"; for (m_Node *cur=m_head; cur!=NULL; cur=cur->m_next) std::cout << cur->m_item << std::endl; std::cout << "End of printed list\n\n"; return;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

m_size=2

m_item m_next

66

Page 67: Программирование

Работа со стеком

5. Печать элементовvoid CStack::Print(){ std::cout << "\nPrinting stack, size = " << m_size <<"\n"; for (m_Node *cur=m_head; cur!=NULL; cur=cur->m_next) std::cout << cur->m_item << std::endl; std::cout << "End of printed list\n\n"; return;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

m_size=2

m_item m_next

cur

cout

67

Page 68: Программирование

Работа со стеком

5. Печать элементовvoid CStack::Print(){ std::cout << "\nPrinting stack, size = " << m_size <<"\n"; for (m_Node *cur=m_head; cur!=NULL; cur=cur->m_next) std::cout << cur->m_item << std::endl; std::cout << "End of printed list\n\n"; return;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

m_size=2

m_item m_next

cur

cout

68

Page 69: Программирование

Работа со стеком

5. Печать элементовvoid CStack::Print(){ std::cout << "\nPrinting stack, size = " << m_size <<"\n"; for (m_Node *cur=m_head; cur!=NULL; cur=cur->m_next) std::cout << cur->m_item << std::endl; std::cout << "End of printed list\n\n"; return;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

m_size=2

m_item m_next

cur

69

Page 70: Программирование

Работа со стеком

6. Очистка памятиCStack::~CStack(void){ m_Node *cur=NULL; while (m_head!=NULL) { cur=m_head; m_head = m_head->m_next; delete cur; }}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head m_item m_next

70

Page 71: Программирование

Работа со стеком

6. Очистка памятиCStack::~CStack(void){ m_Node *cur=NULL; while (m_head!=NULL) { cur=m_head; m_head = m_head->m_next; delete cur; }}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head m_item m_next

cur

71

Page 72: Программирование

Работа со стеком

6. Очистка памятиCStack::~CStack(void){ m_Node *cur=m_head; while (m_head!=NULL) { cur=m_head; m_head = m_head->m_next; delete cur; }}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head m_item m_next

cur

72

Page 73: Программирование

Работа со стеком

6. Очистка памятиCStack::~CStack(void){ m_Node *cur=m_head; while (m_head!=NULL) { cur=m_head; m_head = m_head->m_next; delete cur; }}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head m_item m_next

cur

73

Page 74: Программирование

Работа со стеком

6. Очистка памятиCStack::~CStack(void){ m_Node *cur=m_head; while (m_head!=NULL) { cur=m_head; m_head = m_head->m_next; delete cur; }}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

cur

74

Page 75: Программирование

Работа со стеком

6. Очистка памятиCStack::~CStack(void){ m_Node *cur=m_head; while (m_head!=NULL) { cur=m_head; m_head = m_head->m_next; delete cur; }}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

m_size=2

cur

75

Page 76: Программирование

Работа со стеком

6. Очистка памятиCStack::~CStack(void){ m_Node *cur=m_head; while (m_head!=NULL) { cur=m_head; m_head = m_head->m_next; delete cur; }}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_item m_next

m_head

m_size=2

cur

76

Page 77: Программирование

Работа со стеком

6. Очистка памятиCStack::~CStack(void){ m_Node *cur=m_head; while (m_head!=NULL) { cur=m_head; m_head = m_head->m_next; delete cur; }}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_head

m_size=2

cur

77

Page 78: Программирование

Работа со стеком

6. Очистка памятиCStack::~CStack(void){ m_Node *cur=m_head; while (m_head!=NULL) { cur=m_head; m_head = m_head->m_next; delete cur; }}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_head

m_size=2

cur

78

Page 79: Программирование

Работа со стеком

6. Очистка памятиCStack::~CStack(void){ m_Node *cur=m_head; while (m_head!=NULL) { cur=m_head; m_head = m_head->m_next; delete cur; }}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

m_head

m_size=2

79

Page 80: Программирование

Подведем итоги: класс CStack: описание #pragma onceclass CStack // Описание расположено в файле Stack.h{ struct m_Node { m_Node *m_next; int m_item; }; m_Node *m_head; int m_size;public: CStack() {m_head=NULL; m_size=0;} //Constructor ~CStack(); // Destructor void Push(int item); int Pull(); void Print();};

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

-m_head-m_size

CStack

+CStack+~CStack+Push+Pull+Print

-m_next-m_item

m_Node

80

Page 81: Программирование

Подведем итоги: класс CStack: реализация

#include "StdAfx.h"#include "Stack.h"

CStack::~CStack(void) // Реализация: файл CStack.cpp{ m_Node *cur=m_head; while (m_head!=NULL) { cur=m_head; m_head = m_head->m_next; delete cur; }}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

81

Page 82: Программирование

Подведем итоги: класс CStack: реализацияvoid CStack::Push(int item) // Продолжение файла CStack.cpp{ m_Node *cur=new m_Node; cur->m_item = item; cur->m_next = m_head; m_head = cur; m_size++; return;}int CStack::Pull(){ int item=m_head->m_item; m_Node* tmp=m_head; m_head=m_head->m_next; delete tmp; m_size--; return item;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

82

Page 83: Программирование

Подведем итоги: класс CStack: реализация

void CStack::Print() // Окончание файла CStack.cpp { std::cout << "\nPrinting stack, size = " << m_size <<"\n"; for (m_Node *cur=m_head; cur!=NULL; cur=cur->m_next) std::cout << cur->m_item << std::endl; std::cout << "End of printed list\n\n"; return;}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

83

Page 84: Программирование

Подведем итоги: класс CStack: тестирующая функция main

#include "stdafx.h"using namespace std;

int main() // файл MyStack.cpp{ char k='0'; int item; CStack MyStack;

cout << "\na - add an element to the stack"; cout << "\nd - delete the last element"; cout << "\np - print the stack"; cout << "\nesc - exit\n";

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

84

Page 85: Программирование

Подведем итоги: класс CStack: тестирующая функция main

while (cout << "\nEnter:", k=_getche(), k!=27) { switch (k) { case 'a': { cout<<"\nEnter an item: "; cin >> item;

MyStack.Push(item); cout <<"The item has been added\n"; break;

} case 'd': cout << "\nDeleted. The item is "<<MyStack.Pull() << endl; break; case 'p': MyStack.Print(); break; } } return 0; //Destructor will be called here}

5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных

85

Page 86: Программирование

Шаблон классов – класс, в котором определены данные и методы, но фактический тип (типы) данных задаются в качестве параметра (параметров) при создании объекта класса.

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

Основные свойства шаблона классов: Шаблон позволяет передать в класс один или несколько типов

в виде параметров Параметрами шаблона могут быть не только типы, но и

константные выражения Объявление шаблона должно быть только глобальным Статические члены-данные специфичны для каждой

реализации шаблона Спецификация и реализация шаблона классов при раздельной

компиляции обязательно должны находиться в одном файле

5. Объектно-ориентированное программирование 5.5. Шаблоны классов

86

Page 87: Программирование

Объявление шаблона классов

Объявление шаблона классов начинается со строки, имеющей следующий формат:

template <class Параметр_Типа1, … , class Параметр_ТипаN>

Параметр_типа – вводимый пользователем идентификатор, который затем используется в реализации как имя типа.

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

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

template <class Параметр_Типа1, … , class Параметр_ТипаN>

Тип_функции Имя_шаблона < Параметр_Типа1, … , Параметр_ТипаN>

::Имя_функции (список параметров функции)

5. Объектно-ориентированное программирование 5.5. Шаблоны классов

87

Page 88: Программирование

Объявление шаблона классов

Параметры шаблона могут иметь значения по умолчанию. В этом случае в объявлении шаблона классов в угловых скобках после имени параметра типа ставится знак = , а за ним указывается значение по умолчанию.

Например,

template <class U=int, int Size=100>

5. Объектно-ориентированное программирование 5.5. Шаблоны классов

88

Page 89: Программирование

Объявление объектов шаблона классов

При объявлении переменных шаблона классов (объектов шаблона) создается конкретная реализация шаблона с типом, указанным в качестве параметра типа.

Объявление объекта шаблона классов имеет следующий формат:

Имя_Шаблона <Тип1, … , ТипN> Имя_Объекта;

5. Объектно-ориентированное программирование 5.5. Шаблоны классов

89

Page 90: Программирование

Пример шаблона классов: массив как объект Объявление класса:

template <class U=int, int Size=100>class MyArray{ U m_array [Size]; public: MyArray(void) {for (int i=0; i<=Size-1; i++) m_array[i]=0;} ~MyArray(void) {} U Get (int i); void Put (int i, U x); void Print(void) {for (int i=0; i<=Size; i++) std:: cout << m_array[i] << " " ;}};

5. Объектно-ориентированное программирование 5.5. Шаблоны классов

90

Page 91: Программирование

Пример шаблона классов: массив как объект Определения методов

template <class U, int Size>U MyArray < U, Size>::Get (int i){ if (i<0) i=0; if (i>Size-1) i=Size-1; return m_array[i];}

template <class U, int Size>void MyArray < U, Size>::Put (int i, U x){ if (i<0) i=0; if (i>Size-1) i=Size-1; m_array[i]=x; return; }

5. Объектно-ориентированное программирование 5.5. Шаблоны классов

91

Page 92: Программирование

Пример шаблона классов: массив как объект Функция main

int main(){ MyArray <double, 5> darray; MyArray <> iarray;

darray.Put(1,3.14); iarray.Put(0,2); darray.Put(0,iarray.Get(0)); darray.Print();

_getch(); return 0; }

5. Объектно-ориентированное программирование 5.5. Шаблоны классов

92

Page 93: Программирование

Шаблон класса стек . Файл TStack.cpp

#pragma once#include "StdAfx.h“

template <class T> class TStack{ struct m_Node { m_Node *m_next;

T m_item; }; m_Node *m_head; int m_size;

5. Объектно-ориентированное программирование 5.5. Шаблоны классов

93

Page 94: Программирование

Шаблон класса стек. Файл TStack.cpp (продолжение)

public: TStack(): m_head(NULL), m_size(0){ } //Constructor ~TStack(); // Destructor void Push(T item); T Pull(); void Print(); //works only with simple types void Interpush(); void Interpull();

};

5. Объектно-ориентированное программирование 5.5. Шаблоны классов

94

Page 95: Программирование

Шаблон класса стек. Файл TStack.cpp (продолжение)

template <class T>TStack<T>::~TStack(void) // Destructor {

m_Node *cur=m_head;while (m_head!=NULL){

cur=m_head; m_head = m_head->m_next;delete cur;

}}

5. Объектно-ориентированное программирование 5.5. Шаблоны классов

95

Page 96: Программирование

Шаблон класса стек. Файл TStack.cpp (продолжение)

template <class T>void TStack<T>::Push(T item){

m_Node *cur=new m_Node;cur->m_item = item;cur->m_next = m_head;m_head = cur;m_size++;return;

}

5. Объектно-ориентированное программирование 5.5. Шаблоны классов

96

Page 97: Программирование

Шаблон класса стек. Файл TStack.cpp (продолжение)

template <class T>T TStack<T>::Pull(){

T item=m_head->m_item;m_Node* tmp=m_head;m_head=m_head->m_next;delete tmp;m_size--;return item;

}

5. Объектно-ориентированное программирование 5.5. Шаблоны классов

97

Page 98: Программирование

Шаблон класса стек. Файл TStack.cpp (продолжение)

template <class T>void TStack<T>::Print(){

std::cout << "\nPrinting stack, size = " << m_size <<"\n";for (m_Node *cur=m_head; cur!=NULL; cur=cur->m_next)

std::cout << cur->m_item << std::endl;std::cout << "End of printed list\n\n";return;

}

5. Объектно-ориентированное программирование 5.5. Шаблоны классов

98

Page 99: Программирование

Шаблон класса стек. Файл TStack.cpp (продолжение)

template <class T>void TStack<T>::Interpush(){

T item;cout<<"\nEnter an item: "; cin >> item; Push(item);cout <<"The item has been added\n";return;

}

template <class T>void TStack<T>::Interpull(){

cout << "\nDeleted. The item is "<<Pull() << endl;return;

}

5. Объектно-ориентированное программирование 5.5. Шаблоны классов

99

Page 100: Программирование

Шаблон класса стек. Файл MyTStack.cpp (продолжение)

#include "stdafx.h"#include "TStack.cpp"using namespace std;

int main(){ TStack <double> MyStack; const char *menu[ ][2]= {{"a"," - add an element to the stack"}, {"d"," - delete the last element"}, {"p"," - print the stack"}, {"e"," - exit\n"}}; int size_menu = (sizeof menu)/(sizeof menu[0][0])/2; for (int i=0; i<=size_menu-1; i++)cout << endl << menu[i][0]<<menu[i][1];

5. Объектно-ориентированное программирование 5.5. Шаблоны классов

100

Page 101: Программирование

Шаблон класса стек. Файл MyStack.cpp (продолжение)

while (true) { cout << "\nEnter:"; char k= _getche();

if (k==*menu[0][0]) MyStack.Interpush(); if (k==*menu[1][0]) MyStack.Interpull(); if (k==*menu[2][0]) MyStack.Print(); if (k==*menu[size_menu-1][0]||k==27) break;

} return 0; //Destructor will be called here}

5. Объектно-ориентированное программирование 5.5. Шаблоны классов

101

Page 102: Программирование

5. Объектно-ориентированное программирование 5.6. Перегрузка операций

102

В языке С++ операторы рассматриваются как функции, имеющие следующий прототип:

Имя_Типа operator @ (список_параметров);Здесь символом @ обозначено имя оператора

Операторы, как и функции, можно перегружать. Перегружать можно все существующие в С++ операторы, кроме: .

(точка, оператор доступа к члену класса), .*(оператор доступа к члену класса через указатель), :: (оператор разрешения области видимости, :? (условный оператор), #,## (препроцессорные операторы), sizeof и typeof, операторы преобразования типов данных static_cast, const_cast, reinterpret_cast, dynamic_cast.

Перегруженные операторы можно определять и как члены класса, для которого выполняется перегрузка и как функции не члены класса (часто – дружественные функции).

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

Page 103: Программирование

5. Объектно-ориентированное программирование 5.6. Перегрузка операций

103

Перегрузка операторов должна удовлетворять следующим требованиям: не допускается перегрузка операторов со встроенными типами

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

нельзя вводить новые операторы; нельзя изменять количество параметров оператора; ассоциативность перегруженных операторов не изменяется; приоритеты перегруженных операторов не изменяются; оператор не может иметь аргументов по умолчанию, за

исключением оператора вызова функции (); оператор не может иметь неопределенное количество

параметров, за исключением оператора вызова функции (). Если оператор перегружен как член класса, то он не должен

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

Page 104: Программирование

5. Объектно-ориентированное программирование 5.6. Перегрузка операций

104

Рассмотрим перегрузку операций сразу на примере шаблона класса CVecn, позволяющего работать с n-мерными векторами, заданными своими координатами в прямоугольной системе координат.

Внутренне представление этого вектора – одномерный массив элементов типа double размером n элементов.

Интерфейс должен обеспечивать нумерацию элементов вектора, начиная с 1 и заканчивая n.

Page 105: Программирование

5. Объектно-ориентированное программирование 5.6. Перегрузка операций

105

template <int Size=3>class CVecn{ double m_array [Size]; public: CVecn (void) {for (int i=0; i<=Size-1; i++) m_array[i]=0;} ~CVecn (void) {}

CVecn operator -(); CVecn operator +(CVecn r); CVecn operator -(CVecn r); double operator *(CVecn r);

CVecn operator *(double r); friend CVecn operator *(double l, CVecn r) {for (int i=0; i<=Size-1; i++) r.m_array[i]*=l; return r;}

bool operator ==(CVecn r); bool operator !=(CVecn r);

double& operator [] (int i);};

Page 106: Программирование

5. Объектно-ориентированное программирование 5.8. Перегрузка операций

106

Унарные операторы Могут быть перегружены как нестатические члены класса без

параметров:

Имя_Типа operator @ ( );

здесь @ обозначает один из следующих унарных операторов:& * + - ~ !

CVecn operator - ();… template <int Size>CVecn <Size> CVecn <Size>::operator -(){ for (int i=0; i<=Size-1; i++) m_array[i]=-m_array[i]; return *this;}

Page 107: Программирование

5. Объектно-ориентированное программирование 5.8. Перегрузка операций

107

Унарные операторы Или могут быть перегружены как (дружественные) функции не

члены класса с одним параметром:

Имя_Типа operator @ (параметр);

здесь @ обозначает один из следующих унарных операторов:& * + - ~ !

friend CVecn operator - (CVecn r){ for (int i=0; i<=Size-1; i++) r.m_array[i]=-m_array[i]; return *this;}

Внимание! Если дружественная функция объявляется для шаблона класса и ее аргументами являются специализации шаблона, то определение этой функции должно находиться внутри класса!!!

Page 108: Программирование

5. Объектно-ориентированное программирование 5.8. Перегрузка операций

108

Оператор присваивания Оператор присваивания может быть перегружен только как

нестатический член класса и должен иметь следующий прототип:

Имя_Класса& operator = (const Имя_Класса &Имя_Параметра);

Если оператор присваивания не определен в классе, то компилятор генерирует оператор присваивания по умолчанию, коорый выполняет почленное копирование атрибутов класса.

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

При реализации оператора присваивания следует проверять возможность присваивания объекта самому себе.

Page 109: Программирование

5. Объектно-ориентированное программирование 5.6. Перегрузка операций

109

Оператор присваивания Оператор присваивания может быть перегружен только как

нестатический член класса и должен иметь следующий прототип:

Имя_Класса& operator = (const Имя_Класса &Имя_Параметра);

В нашем случае переопределять оператор присваивания не надо. В принципе, это можно было сделать так:

CVecn& operator = (const CVecn& r);… template <int Size>CVecn <Size> & CVecn <Size>::operator =(const CVecn <Size>

&r ){ if (&r !=this) for (int i=0; i<=Size-1; i++) m_array[i]=r.m_array[i]; return *this;}

Page 110: Программирование

5. Объектно-ориентированное программирование 5.6. Перегрузка операций

110

Оператор индексирования Оператор индексирования может быть перегружен только как

нестатический член класса с одним параметром – значением индекса:

Имя_Типа& operator [] = (const int& i);

double& operator [ ] (const int &i);… template <int Size>double& CVecn <Size>::operator [](const int& i){ if (i<1) return m_array [0]; if (i>Size) return m_array [Size-1]; return m_array [i-1];}

Page 111: Программирование

5. Объектно-ориентированное программирование 5.6. Перегрузка операций

111

Бинарные операторы Бинарные операторы могут быть перегружены как нестатические

члены класса с одним параметром – значением второго (правого операнда:

Имя_Типа operator @ (Тип_Параметра Имя_Параметра);

здесь @ обозначает один из следующих бинарных операторов:+ - * / % == <= >= != && || << >>

CVecn operator +(CVecn r);… template <int Size>CVecn <Size> CVecn <Size>::operator +(CVecn<Size> r){ for (int i=0; i<=Size-1; i++) m_array[i]+=r.m_array[i]; return *this;}

Page 112: Программирование

5. Объектно-ориентированное программирование 5.8. Перегрузка операций

112

Бинарные операторы Бинарные операторы могут быть перегружены как нестатические

члены класса с одним параметром – значением второго (правого операнда:

Имя_Типа operator @ (Тип_Параметра Имя_Параметра);

здесь @ обозначает один из следующих бинарных операторов:+ - * / % == <= >= != && || << >>

CVecn operator -(CVecn r);… template <int Size>CVecn <Size> CVecn <Size>::operator -(CVecn<Size> r){ for (int i=0; i<=Size-1; i++) m_array[i]-=r.m_array[i]; return *this;}

Page 113: Программирование

5. Объектно-ориентированное программирование 5.8. Перегрузка операций

113

double operator * (CVecn r); CVecn operator * (double r);… template <int Size>double CVecn <Size>::operator *(CVecn<Size> r){

double s=0;for (int i=0; i<=Size-1; i++) s+=m_array[i]*m_array[i]; return s;

}

template <int Size>CVecn <Size> CVecn <Size>::operator *(double r){

for (int i=0; i<=Size-1; i++) m_array[i]*=r; return *this;

}

Page 114: Программирование

5. Объектно-ориентированное программирование 5.8. Перегрузка операций

114

bool operator ==(CVecn r);bool operator !=(CVecn r); … template <int Size>bool CVecn <Size>::operator ==(CVecn<Size> r){ for (int i=0; i<=Size-1; i++) if (m_array[i] != r.m_array[i]) return false; return true;}

template <int Size>bool CVecn <Size>::operator !=(CVecn<Size> r){ for (int i=0; i<=Size-1; i++)if (m_array[i] != r.m_array[i])return true; return false;}

Page 115: Программирование

5. Объектно-ориентированное программирование 5.6. Перегрузка операций

115

Бинарные операторы Бинарные операторы также могут быть перегружены как не члены

класса с двумя параметрами – левым и правым операндами:

Имя_Типа operator @ (Тип_Пар Имя_Пар, Тип_Пар Имя_Пар );

здесь @ обозначает один из следующих бинарных операторов:+ - * / % == <= >= != && || << >>

friend CVecn operator *(double l, CVecn r) {for (int i=0; i<=Size-1; i++) r.m_array[i] *= l; return r;}

Внимание! Если дружественная функция объявляется для шаблона класса и ее аргументами являются специализации шаблона, то определение этой функции должно находиться внутри класса!!!

Page 116: Программирование

5. Объектно-ориентированное программирование 5.6. Перегрузка операций

116

Перегрузка других операторов Составные операторы присваивания (+= -= *= /=) могут быть

перегружены как нестатические члены класса:

Имя_Класса& operator @ (const Имя_Класса& Имя_Параметра );

Операторы инкремента ++ и декремента -- могут быть перегружены как члены класса без аргументов или как не члены класса с одним аргументом. Для того, чтобы префиксные операторы отличать от постфиксных, в объявлении последних вводят дополнительный фиктивный параметр типа int .

Имя_Класса operator @ (); //префиксный

Имя_Класса operator @ (int); //постфиксный

Имя_Класса operator @ (Имя_Класса& Имя_Параметра ); Имя_Класса operator @ (Имя_Класса& Имя_Параметра ,int);

Page 117: Программирование

5. Объектно-ориентированное программирование 5.6. Перегрузка операций

117

Перегрузка других операторов Оператор вызова функции ( ) может быть перегружен только как

нестатический члены класса:

Имя_Типа operator @ (список_параметров);

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

Операторы преобразования типа (конвертер) –функция-член класса, которая преобразует тип объекта класса в некоторый другой тип. Конвертор имеет следующий прототип:

operator Имя_Типа ();

Здесь Имя_Типа задает тип данных (встроенный или пользовательский), к которому приводится объект. Конвертер может вызываться как явно, так и неявно – при преобразованиях типов в выражениях, вызове функций и т.п.

Page 118: Программирование

5. Объектно-ориентированное программирование 5.8. Перегрузка операций

118

Перегрузка других операторов Перегруженные операторы >> и << для ввода и вывода. Для

перегрузки определяются как дружественные операторы класса, которые имеют следующие прототипы:

friend istream& operator >> (istream&, Имя_Класса& Имя_параметра);friend ostream& operator << (ostream&, const Имя_Класса& Имя_параметра);

Примеры перегрузки операторов, не рассмотренных подробно в настоящем разделе будут приведены в разделе «Абстрактные типы данных»

Перегрузку операторов new, delete, доступа к классам предлагается рассмотреть, при необходимости, самостоятельно.

Добрый совет: используйте перегрузку операторов только там, где сохраняется их первоначальный смысл, и где это действительно необходимо.

Page 119: Программирование

5. Объектно-ориентированное программирование 5.8. Перегрузка операций

119

Вернемся еще раз к описанию шаблона класса CVecn

template <int Size=3>class CVecn{ double m_array [Size]; public: CVecn (void) {for (int i=0; i<=Size-1; i++) m_array[i]=0;} ~CVecn (void) {}

CVecn operator -(); CVecn operator +(CVecn r); CVecn operator -(CVecn r); double operator *(CVecn r);

CVecn operator *(double r); friend CVecn operator *(double l, CVecn r) {for (int i=0; i<=Size-1; i++) r.m_array[i]*=l; return r;}

bool operator ==(CVecn r); bool operator !=(CVecn r);

double& operator [] (int i);};

Page 120: Программирование

template <int Size>CVecn <Size> CVecn <Size>::operator - (){ for (int i=0; i<=Size-1; i++) m_array[i]=-m_array[i]; return *this;}

template <int Size>CVecn <Size> CVecn <Size>::operator +(CVecn<Size> r){ for (int i=0; i<=Size-1; i++) m_array[i]+=r.m_array[i]; return *this;}

template <int Size>CVecn <Size> CVecn <Size>::operator -(CVecn<Size> r){ for (int i=0; i<=Size-1; i++) m_array[i]-=r.m_array[i]; return *this;}

5. Объектно-ориентированное программирование 5.8. Перегрузка операций

120

Определения функций (так как это шаблон – все размещаем в одном файле)

Page 121: Программирование

template <int Size>double CVecn <Size>::operator *(CVecn<Size> r){ double s=0; for (int i=0; i<=Size-1; i++) s+=m_array[i]*m_array[i]; return s;}

template <int Size>CVecn <Size> CVecn <Size>::operator *(double r){ for (int i=0; i<=Size-1; i++) m_array[i]*=r; return *this;}

5. Объектно-ориентированное программирование 5.6. Перегрузка операций

121

Определения функций

Page 122: Программирование

template <int Size>bool CVecn <Size>::operator ==(CVecn<Size> r){ for (int i=0; i<=Size-1; i++)if (m_array[i]!=r.m_array[i])return false; return true;}

template <int Size>bool CVecn <Size>::operator !=(CVecn<Size> r){ for (int i=0; i<=Size-1; i++)if (m_array[i]!=r.m_array[i])return true; return false;}

template <int Size>double& CVecn <Size>::operator [](const int& i){ if (i<1) return m_array[0]; if (i>Size) return m_array[Size-1]; return m_array[i-1];}

5. Объектно-ориентированное программирование 5.6. Перегрузка операций

122

Определения функций

Page 123: Программирование

int main(){ const int n=5; CVecn <n> v1; v1[1]=1; v1[2]=2; v1[3]=3; v1[4]=4; v1[5]=10; CVecn <n> v2=v1;

v2[1]=0; v1=v2; cout << endl; for (int i=1; i<=n; i++)cout << v1[i]<<" ";

v1*5; cout << endl; for (int i=1; i<=n; i++)cout << v1[i]<<" ";

v1+v2; cout << endl; for (int i=1; i<=n; i++)cout << v1[i]<<" ";

return 0;}

5. Объектно-ориентированное программирование 5.8. Перегрузка операций

123

Пример программы, использующей класс CVecn

Операции сложения и вычитания

векторов, умножения вектора

на скаляр, изменения знака выполняются

«на месте»: результат

сохраняется в первом операнде

Page 124: Программирование

template <int Size=3>class CVecn{ double m_array [Size]; public: CVecn (void) {for (int i=0; i<=Size-1; i++) m_array[i]=0;} ~CVecn (void) {}

CVecn operator -(); CVecn operator +(CVecn r); CVecn operator -(CVecn r); double operator *(CVecn r);

CVecn operator *(double r); friend CVecn operator *(double l, CVecn r) {for (int i=0; i<=Size-1; i++) r.m_array[i]*=l; return r;}

bool operator ==(CVecn r); bool operator !=(CVecn r);

double& operator [] (int i);};

5. Объектно-ориентированное программирование 5.8. Перегрузка операций

124

В третий раз вернемся к описанию шаблона класса CVecn

Обратите внимание: то, каким образом реализован n-мерный вектор, отделено от

пользователя интерфейсом как стеной. Здесь даже нет ни одной функции для

доступа к полям (типа Set или Get.

Пользователь взаимодействует не с массивом, а, абстрагируясь от реализации ,

с привычным ему n-мерным вектором, элементы которого нумеруются от 1 до n

Page 125: Программирование

Абстрактный тип данных (АТД – abstract data type) – это множество значений и совокупность операций над этими значениями этого типа, доступ к которым осуществляется только через интерфейс.

Для представления АТД используются структуры данных, которые представляют собой набор переменных, возможно, различных типов данных, объединенных определенным образом.

5. Объектно-ориентированное программирование 5.9. Абстрактные типы данных

125

Программа Структура

данных

Добавить

Удалить

Найти

Отобразить

Запрос на выполнение операции

Результат выполнения операции

Page 126: Программирование

Разработка абстрактных моделей для данных и способов обработки этих данных – важнейший этап решения задач с помощью ЭВМ.

С помощью АТД мы представляем данные, которые используются в реальном мире и при построении математических моделей, в виде структур данных, которые могут быть созданы средствами языка программирования.

Создание АТД предполагает полное сокрытие реализации АТД в виде структур данных от пользователя.

Set – Get стиль доступа к АТД карается расстрелом!!! Реализация АТД предполагает расширение понятия операции над

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

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

5. Объектно-ориентированное программирование 5.7. Абстрактные типы данных

126

Page 127: Программирование

5. Объектно-ориентированное программирование 5.9. Абстрактные типы данных

class CCmplx // file Cmplx.h{ double m_re; double m_im;

public: CCmplx(double re=0, double im=0):m_re(re), m_im(im){} //CCmplx z1(1,0), z2; z2=CCmplx(1,1); ~CCmplx(void){}

// функции для взятия вещественной и мнимой части можно определить так: double &Re() {return m_re;} // z1.Re()=5; double &Im() {return m_im;} // double r1=z1.Im();

// и одновременно так: friend double& Re(CCmplx &z){return z.m_re;} // Re(z1)=5; friend double& Im(CCmplx &z){return z.m_im;} // double r1=Im(z1);

// или переопределить для этого оператор [ ] double& operator [ ] (int i){if (i<=1)return m_re; else return m_im;} // z1[1] = z2[2]

127

Page 128: Программирование

5. Объектно-ориентированное программирование 5.9. Абстрактные типы данных

// file Cmplx.h (continuation)

// этот оператор присваивания перегружать необязательно: // CCmplx& operator = (CCmplx z) {if (&z !=this) {m_re=z.m_re; m_im=z.m_im; return *this;}}

// если хотим присваивать комплексному double надо перегрузить так: CCmplx& operator = (double r){m_re=r; m_im=0; return *this;} // z1=5;

//Функциональный объект (перегрузка оператора вызова функции) CCmplx& operator () (double x=0, double y=0) {m_re=x; m_im=y; return *this;} // z2(1,3); z1=z2(2,2)

// Конвертер из CCmplx в double (вызывается явно или неявно) operator double (){return m_re;} // r1= z1; r1 =double(z2); r1= static_cast <double> (z1);

// Некорректное переопределение унарного -// CCmplx operator -(){m_re=-m_re; m_im=-m_im; return *this;} // z2=-z1 – изменится знак z1 !!!

// Корректно сделать так: CCmplx operator - (){return CCmplx(-m_re, -m_im);} // правильно CCmplx operator + (){return *this;} // здесь можно оставить и так

128

Page 129: Программирование

5. Объектно-ориентированное программирование 5.9. Абстрактные типы данных

// file Cmplx.h (continuation)

CCmplx operator ++ () {++m_re; return *this;} // prefix z1=++z2; CCmplx operator ++ (int) {m_re++; return *this;} //postfix z1=z2++; (выполняется как prefix)

CCmplx operator +(CCmplx z) {return CCmplx (m_re+z.m_re, m_im+z.m_im);} // z3=z1+z2; CCmplx operator - (CCmplx z) {return CCmplx (m_re-z.m_re, m_im-z.m_im); } // z3=z1+z2; CCmplx operator * (CCmplx z); // z3=z1*z2; CCmplx operator / (CCmplx z); //z3=z1/z2;

CCmplx CCmplx::operator *(CCmplx z) // file Cmplx.cpp{ return CCmplx (m_re*z.m_re - m_im*z.m_im, m_re*z.m_im + m_im*z.m_im); }

CCmplx CCmplx::operator /(CCmplx z){ double d=z.m_re*z.m_re + z.m_im*z.m_im; return CCmplx((m_re*z.m_re+m_im*z.m_im)/d, (m_im*z.m_re+m_re*z.m_im)/d); }

129

Page 130: Программирование

5. Объектно-ориентированное программирование 5.7. Абстрактные типы данных

// file Cmplx.h (continuation)

CCmplx operator + (double r) {return CCmplx (m_re+r, m_im);} // z2=z1+r1; CCmplx operator - (double r) {return CCmplx (m_re-r, m_im);} // z2=z1-r1; CCmplx operator * (double r) {return CCmplx (m_re*r, m_im*r);} // z2=z1*r1; CCmplx operator / (double r) {return CCmplx (m_re/r, m_im/r);} // z2=z1/r1;

// Можно так: // CCmplx operator +=(CCmplx r) {m_re += r.m_re; m_im += r.m_im; return *this;} // z1+=z2;

// Красивее использовать ранее переопределенные арифметические операторы CCmplx operator += (CCmplx z) {return (*this = *this + z); } // z1+=z2; CCmplx operator -= (CCmplx z) {return (*this = *this - z) ; } // z1-=z2; CCmplx operator *= (CCmplx z); {return (*this = *this * z) ; } // z1*=z2; CCmplx operator /= (CCmplx z); {return (*this = *this / z) ; } // z1/=z2;

CCmplx operator += (double r) {m_re+=r; return *this;} // z1+=r1; CCmplx operator -= (double r) {m_re-=r; return *this;} // z1-=r2; CCmplx operator *= (double r) {m_re*=r; m_im*=r; return *this;} // z1*=r2; CCmplx operator /= (double r) {m_re/=r; m_im/=r; return *this;} // z1/=r2;

130

Page 131: Программирование

5. Объектно-ориентированное программирование 5.9. Абстрактные типы данных

// file Cmplx.h (continuation)

bool operator ==(CCmplx z) {return (m_re==z.m_re)&&(m_im==z.m_im)?true:false;} bool operator != (CCmplx z) {return (m_re!==z.m_re)||(m_im!=z.m_im)?true:false;} bool operator ==(double r) {return (m_re==r)&&(m_im==0)?true:false;} bool operator != (double r) {return (m_re!=r)||(m_im!=0)?true:false;}

131

Page 132: Программирование

5. Объектно-ориентированное программирование 5.9. Абстрактные типы данных

// file Cmplx.h (continuation)

friend CCmplx operator + (double r, CCmplx z ) {return (z+r);} //z1=5+z2; friend CCmplx operator - (double r, CCmplx z ); //z1=r1-z2; friend CCmplx operator * (double r, CCmplx z ) {return (z*r);} //z1=r1*z2 friend CCmplx operator / (double r, CCmplx z ); //z1=r1/z2

// file Cmplx.cpp// Дружественные функции не являются членами класса CCmplx // (их заголовку в реализации не предшествует конструкция CCmplx::

CCmplx operator -(double r, CCmplx z ){return CCmplx(r-z.m_re, -z.m_im);}CCmplx operator / (double r, CCmplx z ){return(CCmplx(r,0)/z);}

Только работать это не будет из-за наличия конвертора из ССmplx в double. Модуль CCmplx скомпилируется, но как только в Вашей программе появится оператор z1 = 5 + z2, компилятор не будет знать, что делать:а) сконвертировать z2 в double, сложить 5 и то, что получилось при конвертации, присвоить результат z1 (в результате потеряем мнимую часть);б) использовать перегруженный здесь +. На этапе компиляции программы будет выдано сообщение об ошибке. Разумно избавиться от конвертора: operator double (){return m_re;}

132

Page 133: Программирование

5. Объектно-ориентированное программирование 5.9. Абстрактные типы данных

// file Cmplx.h (continuation) friend double operator +=(double &r, CCmplx z ); ` //r1 += z1; friend double operator -=(double &r, CCmplx z ); //r1 -= z1; friend double operator *=(double &r, CCmplx z ); //r1 *= z1; friend double operator /=(double &r, CCmplx z ); //r1 /= z1;

friend bool operator ==(double r, CCmplx z); friend bool operator !=(double r, CCmplx z);

double operator +=(double &r, CCmplx z ){r=r+z.m_re; return r;} // file Cmplx.cppdouble operator -=(double &r, CCmplx z ){r=r-z.m_re; return r;}double operator *=(double &r, CCmplx z ){r=r*z.m_re; return r;};double operator /=(double &r, CCmplx z ){z=r/z; r=z.Re(); return r;} //z передаем по значению!!!

bool operator ==(double l, CCmplx r){return (r.m_re=l)&&(r.m_im=0)?true:false;} bool operator !=(double l, CCmplx r){return (r.m_re!=l)||(r.m_im!=0)?true:false;}

133

Page 134: Программирование

5. Объектно-ориентированное программирование 5.7. Абстрактные типы данных

// file Cmplx.h (continuation) friend std::istream& operator >> (std::istream &str, CCmplx &r); friend std::ostream& operator << (std::ostream& str, CCmplx r);};

std::istream& operator >> (std::istream &str, CCmplx &z) // file Cmplx.cpp{ double re=0, im=0; str>>re>>im; z=CCmplx(re,im); return str;}

std::ostream& operator << (std::ostream& str, CCmplx z){ if (z.m_im<0)return str<<z.m_re<<z.m_im<<"i"; else return str<<z.m_re<<"+"<<z.m_im<<"i";}

134