'

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

Понравилась презентация – покажи это...





Слайд 0

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


Слайд 1

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


Слайд 2

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


Слайд 3

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


Слайд 4

Последствия маленьких ошибок – крах программной системы: 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


Слайд 5

5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera 6 4 июня 1996 года Взрыв ракеты-носителя Ariane 5 спустя 30 секунд после запуска.


Слайд 6

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


Слайд 7

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


Слайд 8

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


Слайд 9

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


Слайд 10

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


Слайд 11

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


Слайд 12

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


Слайд 13

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


Слайд 14

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


Слайд 15

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


Слайд 16

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


Слайд 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


Слайд 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


Слайд 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 << 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


Слайд 20

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


Слайд 21

Работаем с измененным классом 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


Слайд 22

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


Слайд 23

В использующей класс программе ничего менять не надо: 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


Слайд 24

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


Слайд 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 << "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


Слайд 26

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


Слайд 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


Слайд 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 << "\n a="<<m_a<<" k=" << m_k<< " *k="<<*m_k;} }; 5. Объектно-ориентированное программирование 5.3. Инкапсуляция 29


Слайд 29

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


Слайд 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 << "\n a="<<m_a<<" k=" << m_k<< " *k="<<*m_k;} }; 5. Объектно-ориентированное программирование 5.3. Инкапсуляция const, чтобы Вы по глупости не изменили значения полей источника в функции при их копировании Если передавать p не по ссылке, а по значению, произойдет зацикливание функции, так как передача по значению предполагает создание нового объекта и копирование значения, которое тоже выполняется с помощью этой функции 31


Слайд 31

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


Слайд 32

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


Слайд 33

Объекты в памяти 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


Слайд 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


Слайд 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


Слайд 36

Объекты в памяти 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


Слайд 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


Слайд 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


Слайд 39

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


Слайд 40

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


Слайд 41

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


Слайд 42

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


Слайд 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


Слайд 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 m_head cur m_size=0 45


Слайд 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 46


Слайд 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_head m_head cur m_size=0 47


Слайд 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_head m_head cur m_size=0 48


Слайд 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_head m_head cur m_size=1 49


Слайд 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_head m_head m_size=1 50


Слайд 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_head m_head m_size=1 51


Слайд 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_head m_size=1 52


Слайд 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_head m_size=1 cur 53


Слайд 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_head m_size=1 cur 54


Слайд 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_head m_size=1 cur 55


Слайд 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_head m_size=1 cur 56


Слайд 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_head m_size=2 cur 57


Слайд 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_head m_size=2 58


Слайд 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_head m_size=2 59


Слайд 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_head m_size=2 item 60


Слайд 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_head m_size=2 item tmp 61


Слайд 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_head m_size=2 item tmp 62


Слайд 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_head m_size=2 item tmp 63


Слайд 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_head m_size=1 item tmp 64


Слайд 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_head m_size=1 item 65


Слайд 65

Работа со стеком 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_head m_size=2 66


Слайд 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_head m_size=2 cur cout 67


Слайд 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_head m_size=2 cur cout 68


Слайд 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_head m_size=2 cur 69


Слайд 69

Работа со стеком 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_head 70


Слайд 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_head cur 71


Слайд 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_head cur 72


Слайд 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_head cur 73


Слайд 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_head cur 74


Слайд 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_head m_size=2 cur 75


Слайд 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_head m_size=2 cur 76


Слайд 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


Слайд 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


Слайд 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


Слайд 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


Слайд 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


Слайд 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


Слайд 82

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


Слайд 83

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


Слайд 84

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


Слайд 85

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


Слайд 86

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


Слайд 87

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


Слайд 88

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


Слайд 89

Пример шаблона классов: массив как объект Объявление класса: 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


Слайд 90

Пример шаблона классов: массив как объект Определения методов 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


Слайд 91

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


Слайд 92

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


Слайд 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


Слайд 94

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


Слайд 95

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


Слайд 96

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


Слайд 97

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


Слайд 98

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


Слайд 99

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


Слайд 100

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


Слайд 101

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


Слайд 102

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


Слайд 103

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


Слайд 104

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); };


Слайд 105

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; }


Слайд 106

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; } Внимание! Если дружественная функция объявляется для шаблона класса и ее аргументами являются специализации шаблона, то определение этой функции должно находиться внутри класса!!!


Слайд 107

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


Слайд 108

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; }


Слайд 109

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]; }


Слайд 110

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; }


Слайд 111

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; }


Слайд 112

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; }


Слайд 113

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; }


Слайд 114

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;} Внимание! Если дружественная функция объявляется для шаблона класса и ее аргументами являются специализации шаблона, то определение этой функции должно находиться внутри класса!!!


Слайд 115

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


Слайд 116

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


Слайд 117

5. Объектно-ориентированное программирование 5.8. Перегрузка операций 118 Перегрузка других операторов Перегруженные операторы >> и << для ввода и вывода. Для перегрузки определяются как дружественные операторы класса, которые имеют следующие прототипы: friend istream& operator >> (istream&, Имя_Класса& Имя_параметра); friend ostream& operator << (ostream&, const Имя_Класса& Имя_параметра); Примеры перегрузки операторов, не рассмотренных подробно в настоящем разделе будут приведены в разделе «Абстрактные типы данных» Перегрузку операторов new, delete, доступа к классам предлагается рассмотреть, при необходимости, самостоятельно. Добрый совет: используйте перегрузку операторов только там, где сохраняется их первоначальный смысл, и где это действительно необходимо.


Слайд 118

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); };


Слайд 119

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 Определения функций (так как это шаблон – все размещаем в одном файле)


Слайд 120

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 Определения функций


Слайд 121

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 Определения функций


Слайд 122

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


Слайд 123

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


Слайд 124

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


Слайд 125

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


Слайд 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<=1)return m_re; else return m_im;} // z1[1] = z2[2] 127


Слайд 127

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


Слайд 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


Слайд 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


Слайд 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


Слайд 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


Слайд 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


Слайд 133

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


×

HTML:





Ссылка: