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

Презентация:



Advertisements
Похожие презентации
Основы информатики Классы Заикин Олег Сергеевич zaikin.all24.org
Advertisements

Преобразования типов В языке C/C++ имеется несколько операций преобразования типов. Они используются в случае, если переменная одного типа должна рассматриваться.
Лекция 10 ОбъектыЛекция 10 ОбъектыООП Инкапсуляция Возможность совместного хранения данных и кода для их обработки Наследование Возможность расширять существующие.
Инструкции C++ Условная инструкция Формат: if (условие) оператор; else оператор; Пример: if (i!=0) { if (j) j++; if(k) k++; else if(p) k--; } else i--;
Объектно-ориентированное программирование С++. Лекция 6 Карпов В.Э.
1 Переопределение операций Макаревич Л. Г.. 2 Зачем нужна перегрузка операций? class Complex { double re; double im; public: Complex(double r=0, double.
Лекция 13. Введение в ООП. Часть 4 Красс Александр СПбГУ ИТМО, 2008.
Масштаб 1 : Приложение 1 к решению Совета депутатов города Новосибирска от _____________ ______.
Масштаб 1 : Приложение 1 к решению Совета депутатов города Новосибирска от
Прикладное программирование кафедра прикладной и компьютерной оптики Полиморфизм.
Статические поля класса Статические поля хранят данные, общие для всех элементов класса. Статическое поле существует в единственном экземпляре для всех.
Обработка исключительных ситуаций Исключительная ситуация (исключение) – это ошибка, возникающая во время выполнения программы. Например, ошибка работы.
Лекция 4. Введение в С++ Наследование, множественное наследование. Конструкторы, деструкторы. Виртуальные функции.
Наследование Полиморфизм ВЫЗОВ КОНСТРУКТОРОВ И ДЕСТРУКТОРОВ ПРИ НАСЛЕДОВАНИИ.
ОДНОМЕРНЫЕ МАССИВЫ. РАБОТА С ЭЛЕМЕНТАМИ СТРУКТУРИРОВАННЫЕ ТИПЫ ДАННЫХ.
Перегрузка операторов x = a + b результат 1-й операнд2-й операнд оператор По количеству операндов операторы делятся на: унарные (один операнд) бинарные.
Объектно-ориентированный подход в языке C#. Класс в языке C# - ссылочный тип, определенный пользователем. Для классов ЯП C# допустимо только единичное.
Практическое занятие 6. Функции. Большинство языков программирования используют понятия функции и процедуры. C++ формально не поддерживает понятие процедуры,
Урок 2. Информационные процессы в обществе и природе.
Д.з Язык С++ - занятие 31. Задача 1: 1/1 + 1/3 + 1/5 … #include using namespace std; int main() { int n; cin >> n; double sum = 0;// Сумма for.
Транксрипт:

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

Современные программные системы – сложные системы: они отражают сложность реального мира; процесс их разработки сложен (и слабо стандартизирован); программа - дискретная система, а дискретные системы неустойчивы: маленькая ошибка приводит к значительным последствиям. Общие свойства сложных систем: Имеют внутреннюю структуру, то есть состоят из компонент - подсистем, которые, в свою очередь, тоже могут быть разбиты на подсистемы. Внутренние связи подсистем сильнее связей между этими подсистемами. Это дает возможность по отдельности изучать каждую часть. Состоят из ограниченного числа типов подсистем, скомбинированных и организованных различным образом. Являются результатом эволюции более простых систем. 5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera 2

Рост сложности и объема ПО на примере ОС Windows (неофициальные данные): Последствия ошибок: Состоят из ограниченного числа типов подсистем, скомбинированных и организованных различным образом. Являются результатом эволюции более простых систем. 5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera 3 Операционная система Год выпуска Кол-во строк исходного кода Windows NT миллиона Windows NT ,5 миллионов Windows миллионов Windows XP миллионов

Сложности разработки: Служба Microsoft Consulting Services провела анализ результатов выполнения большого количества своих программных проектов. Оказалось, что вероятность провала программных проектов довольно велика. Только 24% проектов можно признать в той или иной степени успешными, 26% не были завершены, 50% столкнулись с большими проблемами, например, бюджет был превышен вдвое или затрачено в 1,5 раза больше времени. 5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera 4

Последствия маленьких ошибок – крах программной системы: 1996 год. Ошибка взятия целой части дробного числа при выходе числа с плавающей точкой за диапазон допустимых 16-битовых целых: double x; … short i = x; … Вместо: double x; … if (abs (x) < ) short i = x; else …; Результат: 5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera 5

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

Способ преодоления сложности – декомпозиция При проектировании сложной программной системы необходимо разделять ее на все меньшие и меньшие подсистемы, каждую из которых можно совершенствовать независимо. Построив модели ограниченного числа подсистем, можно, комбинируя их различным образом, строить множество гораздо более сложных систем. Построив более простую модель, ее можно далее развивать, следуя за развитием системы. В этом случае мы не превысим пропускную способность человеческого мозга: для понимания любого уровня системы необходимо держать в памяти информацию лишь о немногих частях системы. 5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera 7

Алгоритмическая декомпозиция Основана на разделении алгоритмов по модулям системы. Каждый модуль выполняет один из этапов общего процесса. Реализуется средствами структурного программирования Объектно-ориентированная декомпозиция Мир представляется совокупностью автономно действующих объектов, моделирующих объекты реального мира. Каждый объект обладает своим собственным поведением. Послав объекту сообщение, можно попросить его выполнить присущее ему действие. Объекты взаимодействуют друг с другом, моделируя поведение системы, соответствующее более высокому уровню. Реализуется средствами объектно-ориентированного программирования. 5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera 8

Объектно-ориентированное программирование (ООП) – методология программирования, основанная на представлении программы в виде совокупности объектов, каждый из которых является экземпляром определенного класса, а классы могут образовывать иерархию наследования. 5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera 9

Иерархическое упорядочение задач или объектов – важный принцип управления сложностью проекта, лежащий в основе объектно-ориентированного подхода. Структурная иерархия строится по простому принципу разделения целого на составные части: 5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera 10 Животное ТуловищеГолова ГлазаРотУшиЛапыХвост ……

Объектная иерархия строится по принципу наследования свойств родительских (вышележащих) классов объектов дочерними (нижележащими) классами. Родительские классы называют просто родителями (предками), дочерние – потомками Птица, собака, волк – это типы животных, называемые классами. Конкретная реализация того или иного класса, например, кот Матроскин, является объектом данного класса. 5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera 11 Животное Птица Млекопитающее Кошка ВолкСобака Орел Воробей ……

Объект характеризуется: совокупностью своих элементов (и их текущих значений совокупностью допустимых для объекта действий Объединение в едином объекте «материальных» составных частей (обрабатываемых данных), защищенных от внешних воздействий, и действий, манипулирующих этими частями (данными) называют инкапсуляцией. Наследование – это такое отношение между объектами, когда дочерний объект повторяет элементы структуры и поведения родительского. Классы верхних уровней обычно не имеют конкретных экземпляров объектов. (Не существует конкретного живого организма, который назывался бы млекопитающее Бобик). Такие классы называют абстрактными. Конкретные экземпляры объектов относятся, как правило, к классам самых нижних уровней объектной иерархии (собака Бобик, кот Матроскин). Полиморфизм – это свойство различных объектов выполнять одно и то же действие (с одним и тем же названием) по-своему. Родительские типы называют просто родителями (предками), дочерние – потомками 5. Объектно-ориентированное программирование 5.2. Три принципа ООП 12

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

Синтаксис объявления класса, который не является наследником никакого другого класса: class Имя_Класса { закрытые данные и функции спецификатор доступа : данные и функции спецификатор доступа : данные и функции … спецификатор доступа : данные и функции }; 5. Объектно-ориентированное программирование 5.3. Инкапсуляция 14 Данные Имя_Класса Функции

Пример описания простейшего класса, включающего только данные: class СBox { public: double m_length; double m_width; double m_height; }; 5. Объектно-ориентированное программирование 5.3. Инкапсуляция 15 m_length m_width m_height

Пример описания простейшего класса, включающего только данные: class СBox { public: double m_length; double m_width; double m_height; }; 5. Объектно-ориентированное программирование 5.3. Инкапсуляция 16 Спецификатор доступа

Спецификатор доступа определяет, где в программе будут доступны описанные за ним члены класса. Имеются 3 спецификатора доступа: Public – члены класса будут доступны как в классе, так и в любой точке программы внутри области видимости класса, к которому они относятся. Private (спецификатор по умолчанию) – члены класса будут доступны только внутри класса (членам класса) Protected – члены класса будут доступны только внутри класса и внутри потомков класса Действие спецификатора доступа распространяется до следующего спецификатора или до конца описания класса По умолчанию, все члены класса, объявленные после ключевого слова class до первого спецификатора доступа имеют спецификацию доступа private 5. Объектно-ориентированное программирование 5.3. Инкапсуляция 17

Объявление экземпляров класса 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

Первый принцип инкапсуляции: объединение данных и методов. Добавим функцию вычисления объема 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

Поработаем с классом CBox int main() // Working with class CBox { CBox mybox1; // Static allocation mybox1.m_length=2; mybox1.m_width=3; mybox1.m_height=4; cout m_width=6; pmybox2->m_height=7; cout Volume()

Второй принцип инкапсуляции: защита от внешнего вмешательства. Доступ к данным через явный интерфейс 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

Работаем с измененным классом CBox: int main() // Working with modified class CBox { CBox mybox1; mybox1.Setlength(2); mybox1.Setwidth(3); mybox1.Setheight(4); cout

Для чего это нужно: независимость интерфейса от реализации, разрешаются только операции, определенные через интерфейс 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

В использующей класс программе ничего менять не надо: int main() // Working with modified class CBox { CBox mybox1; mybox1.Setlength(2); mybox1.Setwidth(3); mybox1.Setheight(4); cout

Конструкторы Конструктор класса – специальная функция класса, которая вызывается при создании нового объекта класса. Она позволяет инициализировать объекты во время их создания и захватывать ресурсы, необходимые для их функционирования. Конструкторы всегда называются по имени класса и не имеют типа возврата. Компилятор предоставляет два типа конструкторов: конструктор по умолчанию и конструктор копирования: CBox mybox1; // Вызов конструктора по умолчанию … CBox mybox2 = mybox1 // Вызов конструктора копирования Класс может иметь несколько конструкторов, которые можно перегружать Если Вы определили какой-либо свой конструктор копирования, Вы обязаны явно определить конструктор по умолчанию. Стандартный конструктор копирования нельзя использовать при работе с указателями 5. Объектно-ориентированное программирование 5.3. Инкапсуляция 25

Класс 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

В конструкторе инициализацию переменных-членов класса можно делать в теле конструктора: 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

Поработаем с этим классом int main() // Working with class CBox { CBox mybox1; mybox1.Print(); // L=0 W=0 H=0 CBox mybox2(1,2,3); mybox2.Print(); // L=1 W=2 H=3 CBox 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

Стандартный конструктор копирования нельзя использовать, если Вы работаете с членами - указателями 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

Стандартный конструктор копирования нельзя использовать, если Вы работаете с членами - указателями 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

Надо определить свой конструктор копирования 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

Та же программа, теперь дает ожидаемый результат 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

Деструкторы Деструктор класса – специальная функция класса, которая уничтожает объект, когда необходимость в нем отпадает или время его жизни завершено. Имя деструктора совпадает с именем класса, которому предшествует знак ~(тильда). Деструктор не принимает параметров и не возвращает значения. Таким образом, деструктор в классе всегда один. Компилятор предоставляет деструктор по умолчанию. Однако, если Вы захватывали какие-либо ресурсы при создании объекта (например, динамически выделяли память), Вы обязаны переопределить деструктор для корректного освобождения ресурсов Это было сделано в предыдущем примере: ~CPoint() {delete m_k; m_k=NULL;} 5. Объектно-ориентированное программирование 5.3. Инкапсуляция 33

Объекты в памяти CBox box1, box2, box3 5. Объектно-ориентированное программирование 5.3. Инкапсуляция box1box2 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

Указатель 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

Статические переменные или константы - члены класса 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

Объекты в памяти CBox box1, box2, box3; 5. Объектно-ориентированное программирование 5.3. Инкапсуляция box1box2 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

Статические функции - члены класса 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

Константные объекты 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

Организация связанных структур данных. struct Node { Node *link; // Информационная часть inf // … }; Inflink 5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных InflinkInflinkInflink 40

Основные виды связанных динамических структур данных: Линейные списки – данные динамической структуры, которые представляют собой совокупность линейно связанных однородных элементов, для которых разрешается добавлять элементы между любыми двумя другими и удалять любой элемент. InflinkInflinkInflinkInflinkinf link1link2 inf link1link2 inf link1link2 5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных 41

Основные виды связанных динамических структур данных: Кольцевые списки – имеют дополнительную связь между первым и последним элементами. inflinkinflinkinflinkinflinkinflinkinflinkinflinkinflink Очередь – частный случай линейного списка – разрешено только 2 действия – добавление элементов в конец (хвост) и удаление из начала (головы) списка. Стек – частный случай линейного списка – разрешено только 2 действия – добавление и удаление элементов с одного конца (головы) стека. 5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных 42

Основные виды связанных динамических структур данных: Деревья – иерархические динамические структуры произвольной конфигурации. inf link1link2 inf link1link2 inf link1link2 inf link1link2 inf link1link2 inf link1link2 inf link1link2 inf link1link2 5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных 43

Стек как объект-контейнер 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(); // Destructor void Push(int item); int Pull(); void Print(); }; 5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных 44

Работа со стеком 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 cur m_size=0 m_itemm_next 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_itemm_next m_head cur m_size=0 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_itemm_next m_head cur m_size=0 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_itemm_next m_head cur m_size=0 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_itemm_next m_head cur m_size=1 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_itemm_next m_head m_size=1 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_itemm_next m_head m_size=1 51

Работа со стеком 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_itemm_next m_head m_size=1 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_itemm_next m_head m_size=1 cur m_itemm_next 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_itemm_next m_head m_size=1 cur m_itemm_next 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_itemm_next m_head m_size=1 cur m_itemm_next 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_itemm_next m_head m_size=1 cur m_itemm_next 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_itemm_next m_head m_size=2 cur m_itemm_next 57

Работа со стеком 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_itemm_next m_head m_size=2 m_itemm_next 58

Работа со стеком 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_itemm_next m_head m_size=2 m_itemm_next 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_itemm_next m_head m_size=2 m_itemm_next item 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_itemm_next m_head m_size=2 m_itemm_next item tmp 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_itemm_next m_head m_size=2 m_itemm_next item tmp 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_itemm_next m_head m_size=2 m_itemm_next item tmp 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_itemm_next m_head m_size=1 item tmp 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_itemm_next m_head m_size=1 item 65

Работа со стеком 5. Печать элементов void CStack::Print() { std::cout

Работа со стеком 5. Печать элементов void CStack::Print() { std::cout

Работа со стеком 5. Печать элементов void CStack::Print() { std::cout

Работа со стеком 5. Печать элементов void CStack::Print() { std::cout

Работа со стеком 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_itemm_next m_head m_itemm_next 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_itemm_next m_head m_itemm_next cur 71

Работа со стеком 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_itemm_next m_head m_itemm_next cur 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_itemm_next m_head m_itemm_next cur 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_itemm_next m_head cur 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_itemm_next m_head m_size=2 cur 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_itemm_next m_head m_size=2 cur 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_head m_size=2 cur 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 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 79

Подведем итоги: класс CStack: описание #pragma once class 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

Подведем итоги: класс 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

Подведем итоги: класс 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

Подведем итоги: класс CStack: реализация void CStack::Print() // Окончание файла CStack.cpp { std::cout

Подведем итоги: класс CStack: тестирующая функция main #include "stdafx.h" using namespace std; int main() // файл MyStack.cpp { char k='0'; int item; CStack MyStack; cout

Подведем итоги: класс CStack: тестирующая функция main while (cout item; MyStack.Push(item); cout

Шаблон классов – класс, в котором определены данные и методы, но фактический тип (типы) данных задаются в качестве параметра (параметров) при создании объекта класса. Шаблоны классов позволяют многократно использовать один и тот же код, позволяющий компилятору автоматизировать процесс реализации типа. Основные свойства шаблона классов: Шаблон позволяет передать в класс один или несколько типов в виде параметров Параметрами шаблона могут быть не только типы, но и константные выражения Объявление шаблона должно быть только глобальным Статические члены-данные специфичны для каждой реализации шаблона Спецификация и реализация шаблона классов при раздельной компиляции обязательно должны находиться в одном файле 5. Объектно-ориентированное программирование 5.5. Шаблоны классов 86

Объявление шаблона классов Объявление шаблона классов начинается со строки, имеющей следующий формат: template Параметр_типа – вводимый пользователем идентификатор, который затем используется в реализации как имя типа. Если параметр – константное выражение, в списке параметров ключевое слово класс перед ним не указывается. Методы должны быть объявлены как шаблоны функций, поэтому заголовок метода, определение которого находится за пределами спецификации класса, имеет следующий формат: template Тип_функции Имя_шаблона :: Имя_функции ( список параметров функции ) 5. Объектно-ориентированное программирование 5.5. Шаблоны классов 87

Объявление шаблона классов Параметры шаблона могут иметь значения по умолчанию. В этом случае в объявлении шаблона классов в угловых скобках после имени параметра типа ставится знак =, а за ним указывается значение по умолчанию. Например, template 5. Объектно-ориентированное программирование 5.5. Шаблоны классов 88

Объявление объектов шаблона классов При объявлении переменных шаблона классов (объектов шаблона) создается конкретная реализация шаблона с типом, указанным в качестве параметра типа. Объявление объекта шаблона классов имеет следующий формат: Имя_Шаблона Имя_Объекта ; 5. Объектно-ориентированное программирование 5.5. Шаблоны классов 89

Пример шаблона классов: массив как объект Объявление класса: template class MyArray { U m_array [Size]; public: MyArray(void) {for (int i=0; i

Пример шаблона классов: массив как объект Определения методов template U MyArray ::Get (int i) { if (i Size-1) i=Size-1; return m_array[i]; } template void MyArray ::Put (int i, U x) { if (i Size-1) i=Size-1; m_array[i]=x; return; } 5. Объектно-ориентированное программирование 5.5. Шаблоны классов 91

Пример шаблона классов: массив как объект Функция main int main() { MyArray 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

Шаблон класса стек. Файл TStack.cpp #pragma once #include "StdAfx.h template class TStack { struct m_Node { m_Node *m_next; T m_item; }; m_Node *m_head; int m_size; 5. Объектно-ориентированное программирование 5.5. Шаблоны классов 93

Шаблон класса стек. Файл 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

Шаблон класса стек. Файл TStack.cpp (продолжение) template TStack ::~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

Шаблон класса стек. Файл TStack.cpp (продолжение) template void TStack ::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

Шаблон класса стек. Файл TStack.cpp (продолжение) template T TStack ::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

Шаблон класса стек. Файл TStack.cpp (продолжение) template void TStack ::Print() { std::cout

Шаблон класса стек. Файл TStack.cpp (продолжение) template void TStack ::Interpush() { T item; cout > item; Push(item); cout

Шаблон класса стек. Файл MyTStack.cpp (продолжение) #include "stdafx.h" #include "TStack.cpp" using namespace std; int main() { TStack 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

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

5. Объектно-ориентированное программирование 5.6. Перегрузка операций 102 В языке С++ операторы рассматриваются как функции, имеющие следующий прототип: Имя_Типа ( список_параметров ); Здесь обозначено имя оператора Операторы, как и функции, можно перегружать. Перегружать можно все существующие в С++ операторы, кроме:. (точка, оператор доступа к члену класса),.*(оператор доступа к члену класса через указатель), :: (оператор разрешения области видимости, :? (условный оператор), #,## (препроцессорные операторы), sizeof и typeof, операторы преобразования типов данных static_cast, const_cast, reinterpret_cast, dynamic_cast. Перегруженные операторы можно определять и как члены класса, для которого выполняется перегрузка и как функции не члены класса (часто – дружественные функции). Один оператор может быть перегружен несколько раз для различных типов аргументов.

5. Объектно-ориентированное программирование 5.6. Перегрузка операций 103 Перегрузка операторов должна удовлетворять следующим требованиям: не допускается перегрузка операторов со встроенными типами данных, в качестве параметров, тип, по крайней мере одного параметра перегруженного оператора должен быть классом. нельзя вводить новые операторы; нельзя изменять количество параметров оператора; ассоциативность перегруженных операторов не изменяется; приоритеты перегруженных операторов не изменяются; оператор не может иметь аргументов по умолчанию, за исключением оператора вызова функции (); оператор не может иметь неопределенное количество параметров, за исключением оператора вызова функции (). Если оператор перегружен как член класса, то он не должен иметь спецификатор static и его первым операндом по умолчанию является объект класса, вызывающий этот оператор.

5. Объектно-ориентированное программирование 5.6. Перегрузка операций 104 Рассмотрим перегрузку операций сразу на примере шаблона класса CVecn, позволяющего работать с n-мерными векторами, заданными своими координатами в прямоугольной системе координат. Внутренне представление этого вектора – одномерный массив элементов типа double размером n элементов. Интерфейс должен обеспечивать нумерацию элементов вектора, начиная с 1 и заканчивая n.

5. Объектно-ориентированное программирование 5.6. Перегрузка операций 105 template class CVecn { double m_array [Size]; public: CVecn (void) {for (int i=0; i

5. Объектно-ориентированное программирование 5.8. Перегрузка операций 106 Унарные операторы Могут быть перегружены как нестатические члены класса без параметров: Имя_Типа ( ); обозначает один из следующих унарных операторов: & * + - ~ ! CVecn operator - (); … template CVecn CVecn ::operator -() { for (int i=0; i

5. Объектно-ориентированное программирование 5.8. Перегрузка операций 107 Унарные операторы Или могут быть перегружены как (дружественные) функции не члены класса с одним параметром: Имя_Типа ( параметр ); обозначает один из следующих унарных операторов: & * + - ~ ! friend CVecn operator - (CVecn r) { for (int i=0; i

5. Объектно-ориентированное программирование 5.8. Перегрузка операций 108 Оператор присваивания Оператор присваивания может быть перегружен только как нестатический член класса и должен иметь следующий прототип: Имя_Класса& operator = (const Имя_Класса &Имя_Параметра ); Если оператор присваивания не определен в классе, то компилятор генерирует оператор присваивания по умолчанию, коорый выполняет почленное копирование атрибутов класса. Оператор присваивания целесообразно перегружать только в том случае, если дополнительно к копированию атрибутов нужно выполнить еще какие-либо действия. Как правило, это приходится делать, если объект работает с указателями и динамически выделяет память, чтобы избежать простого копирования указателей (см. ранее пример с конструктором копирования). При реализации оператора присваивания следует проверять возможность присваивания объекта самому себе.

5. Объектно-ориентированное программирование 5.6. Перегрузка операций 109 Оператор присваивания Оператор присваивания может быть перегружен только как нестатический член класса и должен иметь следующий прототип: Имя_Класса& operator = (const Имя_Класса &Имя_Параметра ); В нашем случае переопределять оператор присваивания не надо. В принципе, это можно было сделать так: CVecn& operator = (const CVecn& r); … template CVecn & CVecn ::operator =(const CVecn &r ) { if (&r !=this) for (int i=0; i

5. Объектно-ориентированное программирование 5.6. Перегрузка операций 110 Оператор индексирования Оператор индексирования может быть перегружен только как нестатический член класса с одним параметром – значением индекса: Имя_Типа& operator [] = (const int& i); double& operator [ ] (const int &i); … template double& CVecn ::operator [](const int& i) { if (iSize) return m_array [Size-1]; return m_array [i-1]; }

5. Объектно-ориентированное программирование 5.6. Перегрузка операций 111 Бинарные операторы Бинарные операторы могут быть перегружены как нестатические члены класса с одним параметром – значением второго (правого операнда: Имя_Типа ( Тип_Параметра Имя_Параметра ); обозначает один из следующих бинарных операторов: + - * / % == = != && || > CVecn operator +(CVecn r); … template CVecn CVecn ::operator +(CVecn r) { for (int i=0; i

5. Объектно-ориентированное программирование 5.8. Перегрузка операций 112 Бинарные операторы Бинарные операторы могут быть перегружены как нестатические члены класса с одним параметром – значением второго (правого операнда: Имя_Типа ( Тип_Параметра Имя_Параметра ); обозначает один из следующих бинарных операторов: + - * / % == = != && || > CVecn operator -(CVecn r); … template CVecn CVecn ::operator -(CVecn r) { for (int i=0; i

5. Объектно-ориентированное программирование 5.8. Перегрузка операций 113 double operator * (CVecn r); CVecn operator * (double r); … template double CVecn ::operator *(CVecn r) { double s=0; for (int i=0; i

5. Объектно-ориентированное программирование 5.8. Перегрузка операций 114 bool operator ==(CVecn r); bool operator !=(CVecn r); … template bool CVecn ::operator ==(CVecn r) { for (int i=0; i

5. Объектно-ориентированное программирование 5.6. Перегрузка операций 115 Бинарные операторы Бинарные операторы также могут быть перегружены как не члены класса с двумя параметрами – левым и правым операндами: Имя_Типа ( Тип_Пар Имя_Пар, Тип_Пар Имя_Пар ); обозначает один из следующих бинарных операторов: + - * / % == = != && || > friend CVecn operator *(double l, CVecn r) {for (int i=0; i

5. Объектно-ориентированное программирование 5.6. Перегрузка операций 116 Перегрузка других операторов Составные операторы присваивания (+= -= *= /=) могут быть перегружены как нестатические члены класса: Имя_Класса& (const Имя_Класса& Имя_Параметра ); Операторы инкремента ++ и декремента -- могут быть перегружены как члены класса без аргументов или как не члены класса с одним аргументом. Для того, чтобы префиксные операторы отличать от постфиксных, в объявлении последних вводят дополнительный фиктивный параметр типа int. Имя_Класса (); //префиксный Имя_Класса (int); //постфиксный Имя_Класса ( Имя_Класса& Имя_Параметра ); Имя_Класса ( Имя_Класса& Имя_Параметра, int);

5. Объектно-ориентированное программирование 5.6. Перегрузка операций 117 Перегрузка других операторов Оператор вызова функции ( ) может быть перегружен только как нестатический члены класса: Имя_Типа ( список_параметров ); Здесь количество параметров может быть произвольным, и допускается определять значения параметров по умолчанию. Вызывается оператор вызова функции путем применения списка фактических параметров к объекту класса, в котором он определен. Так как в этом случае объект может использоваться как функция, он иногда называется функциональным объектом. Операторы преобразования типа (конвертер) –функция-член класса, которая преобразует тип объекта класса в некоторый другой тип. Конвертор имеет следующий прототип: operator Имя_Типа (); Здесь Имя_Типа задает тип данных (встроенный или пользовательский), к которому приводится объект. Конвертер может вызываться как явно, так и неявно – при преобразованиях типов в выражениях, вызове функций и т.п.

5. Объектно-ориентированное программирование 5.8. Перегрузка операций 118 Перегрузка других операторов Перегруженные операторы >> и > (istream&, Имя_Класса& Имя_параметра ); friend ostream& operator

5. Объектно-ориентированное программирование 5.8. Перегрузка операций 119 Вернемся еще раз к описанию шаблона класса CVecn template class CVecn { double m_array [Size]; public: CVecn (void) {for (int i=0; i

template CVecn CVecn ::operator - () { for (int i=0; i

template double CVecn ::operator *(CVecn r) { double s=0; for (int i=0; i

template bool CVecn ::operator ==(CVecn r) { for (int i=0; i

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

template class CVecn { double m_array [Size]; public: CVecn (void) {for (int i=0; i

Абстрактный тип данных (АТД – abstract data type) – это множество значений и совокупность операций над этими значениями этого типа, доступ к которым осуществляется только через интерфейс. Для представления АТД используются структуры данных, которые представляют собой набор переменных, возможно, различных типов данных, объединенных определенным образом. 5. Объектно-ориентированное программирование 5.9. Абстрактные типы данных 125 Программа Интерфейс Структура данных Добавить Удалить Найти Отобразить … Запрос на выполнение операции Результат выполнения операции

Разработка абстрактных моделей для данных и способов обработки этих данных – важнейший этап решения задач с помощью ЭВМ. С помощью АТД мы представляем данные, которые используются в реальном мире и при построении математических моделей, в виде структур данных, которые могут быть созданы средствами языка программирования. Создание АТД предполагает полное сокрытие реализации АТД в виде структур данных от пользователя. Set – Get стиль доступа к АТД карается расстрелом!!! Реализация АТД предполагает расширение понятия операции над значениями типа данных с помощью интерфейсных процедур и функций. Важный инструмент, позволяющий добиться определения операций над АТД – перегрузка операций. Рассмотрим в качестве примера абстрактного типа данных комплексные числа. 5. Объектно-ориентированное программирование 5.7. Абстрактные типы данных 126

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

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 (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

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

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

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

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

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.cpp double 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

5. Объектно-ориентированное программирование 5.7. Абстрактные типы данных // file Cmplx.h (continuation) friend std::istream& operator >> (std::istream &str, CCmplx &r); friend std::ostream& 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